<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Henrique Dezani on Medium]]></title>
        <description><![CDATA[Stories by Henrique Dezani on Medium]]></description>
        <link>https://medium.com/@henriquedezani?source=rss-3e4ded46e720------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*nUb3_vZbUmjCDXWyWyL77A.png</url>
            <title>Stories by Henrique Dezani on Medium</title>
            <link>https://medium.com/@henriquedezani?source=rss-3e4ded46e720------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 15:59:43 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@henriquedezani/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Flutter e Firebase Machine Learning na prática.]]></title>
            <link>https://medium.com/henrique-dezani/flutter-e-firebase-machine-learning-na-pr%C3%A1tica-55965d9cf491?source=rss-3e4ded46e720------2</link>
            <guid isPermaLink="false">https://medium.com/p/55965d9cf491</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[serviços-cognitivos]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[visão-computacional]]></category>
            <dc:creator><![CDATA[Henrique Dezani]]></dc:creator>
            <pubDate>Fri, 04 Sep 2020 01:19:48 GMT</pubDate>
            <atom:updated>2020-09-04T09:55:18.396Z</atom:updated>
            <content:encoded><![CDATA[<h4>Criando um aplicativo de tradução de textos contidos em imagens.</h4><p>Como pesquisador, já tive a oportunidade de apresentar diversos artigos em países como Itália, Portugal, Espanha, Canadá e África do Sul — obrigado CAPES e CNPq pelos apoios (infelizmente, no momento atual que tanto precisamos, o país não incentiva mais a pesquisa). Continuando, os países que frequentei possuem seus idiomas raízes, mas todos usam inglês (alguns nativamente). Agora me imagino ir para a China, Japão ou Índia, onde, por mais que possam ter o idioma inglês também como um meio de comunicação, as placas, cardápios e avisos em geral são escritos em seus idiomas próprios. Como estarmos preparados para visitar tais países? A solução está na Inteligência Artificial.</p><p>Nos dias atuais, é comum termos um dispositivo móvel por pessoa, quando não dois ou mais, e estes dispositivos, os chamados <em>smartphones</em>, nos trazem uma série de recursos que permitem nos localizarmos (GPS), guardarmos momentos (câmera para fotos e vídeos), conectarmos (WiFi, 4G) e assim por diante. Mais do que isso, estes dispositivos possuem atualmente um alto poder de processamento e capacidade de armazenamento de dados, o que os permitem realizar processamentos complexos, com a execução de um modelo de Rede Neural Artificial, por exemplo. E quando não houver tais poderes? Temos então a computação em nuvem (Cloud Computing) para nos auxiliar, realizando o processamento em servidores da Google, por exemplo, e nos enviando a resposta desejada, em poucos segundos.</p><p>Apenas uma curiosidade: eu iniciei na área de desenvolvimento de aplicativos em 2007, quando ainda não tínhamos o Android e o iOS, mas sim o Symbian, sendo executado nos celulares de ponta da Nokia. Naquela época, eu desenvolvia na linguagem Java usando Java Micro Edition (J2ME), inclusive com conexões ao Sun Spot (<em>Sun Small Programmable Object Technology, </em>mostrado na Figura 1) para obter informações do ambiente, como hoje é feito usando Arduino, Raspberry Pi entre outros. De lá para cá muita coisa evoluiu, tanto em <em>hardware</em>, quanto em sistemas operacionais e linguagens de programação, até chegarmos ao conjunto de tecnologia que estudaremos neste artigo, o Flutter/Dart, Android (mas poderia ser o iOS também) e o <em>Backend as a Service</em> Firebase e seus serviços de Machine Learning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*vZCQExaaogMVmsCCivnS1A.jpeg" /><figcaption>Figura 1. Sun Spot</figcaption></figure><p><a href="https://flutter.dev/">Flutter</a> é um SDK (Software Development Kit) para criação de aplicativos para dispositivos móveis — e também para <em>web</em>, <em>watch</em>, <em>desktop</em>, televisão e outros — desenvolvido e mantido pela Google para criar interfaces nativas de alta qualidade tanto para o iOS quanto para o Android e que faz uso da linguagem de programação <a href="https://dart.dev/">Dart</a>, criada também pela própria Google e que possui uma sintaxe muito similar ao Java, C# e TypeScript, ou seja, com uma única linguagem de programação você criará aplicativos nativos para Android e iOS.</p><p>Gostaria de dizer que eu não pretendo focar na introdução ao Flutter, ou seja, é recomendável que você tenha o ambiente de desenvolvimento instalado e saiba criar, pelo menos, um aplicativo &quot;Hello World&quot; com esta tecnologia. Caso não tenha esses conhecimentos, recomendo que você acesse o <em>link</em> do curso gratuito disponível na Udemy que eu preparei.</p><p><a href="https://www.udemy.com/course/flutter-crie-aplicativos-android-e-ios-com-sdk-mobile-do-google-e-dart/">https://www.udemy.com/course/flutter-crie-aplicativos-android-e-ios-com-sdk-mobile-do-google-e-dart/</a></p><p>O <a href="https://firebase.google.com/">Firebase</a>, da Google, é conhecido com <em>Backend as a Service</em>, ou seja, é uma plataforma que disponibiliza um conjunto de serviços para aplicativos móveis e <em>web</em> prontos, dentre os quais podemos destacar a autenticação, o armazenamento de arquivos, o banco de dados de tempo real, as <em>functions</em> (<em>serverless</em>) e o Machine Learning do qual faremos uso. Na Figura 2 são apresentados os principais serviços do Firebase.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/871/1*x-OTRpG9FpKtisdvasuLJw.png" /><figcaption>Figura 2. Serviços disponíveis no Firebase.</figcaption></figure><h3>1. Criando o aplicativo Flutter</h3><p>Vamos começar criando nosso projeto a partir da execução do comando flutter create --androidx tradutor_app. Depois de criado o projeto, acesse a sua pasta a partir do Visual Studio Code (ou Android Studio, se preferir) e vamos colocar a mão na massa!</p><p>Uma vez criado o projeto, vamos alterar o arquivo lib\main.dart para o código apresentado na Figura 3. Apresentando de uma forma geral, temos a class MyApp retornando o <em>widget</em> MaterialApp, que por sua vez tem o <em>widget</em> HomePage definido no seu atributo home (linha10), ou seja, HomePage consiste no widget a ser exibido quando carregarmos o aplicativo.</p><p>A classe HomePage herda da classe StatefulWidget para que possamos renderizar as atualizações na tela quando tirarmos a foto e realizar a captura e traduação do texto, objetivo do aplicativo. Sendo assim, vamos utilizar a variável texto (String), definida na linha 21, para as operações a seguir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*7LfAxb5zNRuVdZmFkk-lKw.png" /><figcaption>Figura 3. Código inicial com a interface do aplicativo.</figcaption></figure><p>Na Figura 4 é apresentada a tela do aplicativo, após executar o código criando anteriormente. A ideia é simples, o usuário clicará no botão que se encontra no canto inferior direito da tela (FloatingActionButton), capturará uma foto usando a câmera e o sistema apresentará a tradução do texto encontrado nesta foto.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/371/1*HAODLQTfhugICvqZAYpGLw.png" /><figcaption>Figura 4. Aplicativo executado.</figcaption></figure><p>Para realizar nosso objetivo, precisaremos utilizar quatro bibliotecas externas, quais seja, image_picker, firebase_core, firebase_ml_vision e translator. Todas as bibliotecas estão disponíveis no <a href="https://pub.dev/">pub.dev</a>. No projeto, basta abrirmos o arquivo pubspec.yaml e adicionarmos as dependências apresentadas nas linhas 13, 14, 15 e 16da Figura 5. Em seguida, salve o projeto e o Flutter instalará as novas dependências (flutter pub get).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/842/1*oL-SRtx81uQulXjcmtMGfg.png" /><figcaption>Figura 5. Adição das dependências (linhas 13, 14, 15 e 16).</figcaption></figure><p>Uma vez instaladas as dependências, vamos ao código! De volta ao arquivo main.dart, vamos importar, no início do arquivo, nossas bibliotecas. Para tanto, basta adicionar as linhas 4, 5, 6 e 7, conforme apresentado na Figura 6. Além dela, vamos adicionar também a biblioteca dart:io (linha 1) para que possamos manipular o arquivo da imagem obtida com a câmera.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UOg8lFyNe5RcntGcHddqOQ.png" /><figcaption>Figura 6. Importação das bibliotecas (linhas 4, 5, 6 e 7).</figcaption></figure><h3>2. Criando e configurando o Firebase</h3><p>Agora, antes de realmente fazer a &quot;mágica acontecer&quot;, precisamos criar um novo projeto no Firebase e configurarmos o acesso a ele no Flutter/Android. Esta é uma parte bem &quot;burocrática&quot; e que pode se alterar com novas versões das bibliotecas, mas deixarei aqui o caminho das pedras usando as versões disponíveis no momento em que escrevo este artigo.</p><p>O primeiro passo é efetivamente criar o projeto no Firebase. Para tanto, acesse a plataforma a partir do <em>link</em> <a href="https://firebase.google.com/">https://firebase.google.com/</a>, faça o <em>login</em> e acesse o Console. Fique tranquilo, não é necessário cadastrar cartão de crédito ou informar nenhum outro dado a não ser sua própria conta de acesso ao Google (Gmail, por exemplo). Uma vez no console, basta clicar em &quot;Criar novo Projeto&quot; e seguir as instruções a seguir.</p><p>Nas telas apresentadas na Figura 7 nós definimos o nome do projeto, o uso ou não do Google Analytics e a finalização. Em relação ao nome, eu utilizei TradutorApp, mas você pode utilizar o nome que desejar, inclusive o mesmo (se utilizar o mesmo, repare que abaixo de onde você digita o nome aparecerá um id diferente, algo como tradutorapp-2abc1).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/884/1*napchJTv7B06vMbRGhKrVA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/865/1*-8fQ3cOXH0kfyxSAaWV7YQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/1*y4Gipw4TZ7Kc2ac1-XIY4g.png" /><figcaption>Figura 7. Passos para a criação de um projeto no Firebase: (a) Definição do nome, (b) Uso do Google Analytics ou não e (c) Finalização.</figcaption></figure><p>Uma vez criado o projeto, vamos ter acesso ao painel principal. Neste, poderemos escolher uma ou mais plataformas para conectarmos ao projeto, quais sejam: Android, iOS, Web e Unity. Nas telas da Figura 8, vamos escolher o Android (clicando no seu ícone na Figura do lado esquerdo), o que nos levará para a tela à direita. Nesta última, devemos preencher o campo Nome do pacote do Android,definido na criação do projeto Flutter (em geral, se você não definiu um pacote durante a criação, ele será com.example.NOME_DO_APP, no nosso caso com.example.tradutor_app. Preenchido este campo, clique no botão &quot;Registrar app&quot;.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Gd7rOln1BOD9bPYMhYEdFw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/715/1*oQpVdUXje2wrR3ylpn_SBQ.png" /><figcaption>Figura 8. Tela inicial do projeto no Firebase (esquerda) e a adição de um aplicativo Android (direita).</figcaption></figure><p>Após clicarmos em &quot;Registrar app&quot;, far-se-à necessário realizar o <em>download</em> do arquivo google-services.json e adicionar ao nosso projeto Flutter. Depois de feito o <em>download</em>, o arquivo deve ser movido para dentro da pasta android/app conforme apresentado na Figura 9 (à direita). O arquivo google-services.json contém as chaves de acesso que permitirão que nosso aplicativo Flutter acesse os serviços do Firebase (pense nele como se fosse uma string de conexão).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/849/1*g71gXxx4I3dIwRnzKyxFvg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*RsEIkEWuakJmi3B5SUM2mQ.png" /><figcaption>Figura 9. Fazendo o <em>download</em> e adicionando o arquivo google-services.json ao projeto.</figcaption></figure><p>As duas próximas, e últimas, etapas de configuração do Firebase no nosso aplicativo Flutter consistem em adicionar as dependências do google-services aos arquivo build.gradle, disponível na pasta raiz do projeto Android (Figura 10, linha 11) e build.gradle, do arquivo disponível na pasta app do projeto Android (Figura 11, linha 27). Estas configurações permitiram que o nosso aplicativo Flutter, quando compilado para Android, possa acessar os recursos do Firebase. Caso deseje executar o projeto no iPhone, é necessário escolher a plataforma iOS no Firebase e seguir os passos indicados.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*VS7uBiom7Kmzu-K4ZhIXBg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/868/1*H6n5ZH959YZ72xZhYVZCWw.png" /><figcaption>Figura 10. Adicionando o SDK do Firebase no nosso projeto Android.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/777/1*z0TOioefGbNHaDzKxfV8DQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/819/1*Cj51VKEJ1jKFoRPIlSk46Q.png" /><figcaption>Figura 11. Definindo o plugin</figcaption></figure><p>Para concluirmos a configuração, vamos alterar o método main do nosso arquivo main.dart. Primeiro, vamos transformar este método em um método assíncrono (linha 9) para que possamos utilizar a instrução await (linha 11) e aguardar a conexão com o Firebase (feita a partir das chaves disponíveis no arquivo google-services.json).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/1*uX2AGX4NRHcfcXXZb-n5IA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bwVAo1lZf02a5SpJKl0pMQ.png" /><figcaption>Figura 12. Método main atualizado para iniciar a conexão ao Firebase.</figcaption></figure><h3>3. Configurando o Firebase Machine Learning</h3><p>Mais configurações? Sim, mas é a última, prometo. Vamos ao Firebase Machine Learning (ML). O Firebase fornece um conjunto de serviços de Aprendizado de Máquina, tendo os serviços cognitivos de visão como os seus principais (Figura 13). Utilizando o Firebase ML podemos implementar o reconhecimento de texto em imagens (o qual utilizaremos neste artigo), a rotulação de imagens, a detecção e o rastreamento de objetos, a leitura de código de barras, a detecção do idioma de um texto, o reconhecimento de pontos de referência, a detecção facial, entre outros.</p><p>Fugindo um pouco do nosso objetivo principal, o Firebase ML possui vários serviços bem interessantes, dentre eles o de detecção facial. Entretanto, é importante ressaltar que este serviço consiste apenas em detectar e não identificar faces. Caso deseje fazer a identificação, recomendo os <a href="https://azure.microsoft.com/en-us/services/cognitive-services/face/">serviços cognitivos do Microsoft Azure</a> — em breve um artigo sobre como podemos usá-los em nosso aplicativo, aguarde!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/734/1*dhOoTvYDyqbgtj3154UXBg.png" /><figcaption>Figura 13. Serviços disponíveis no Firebase Machine Learning.</figcaption></figure><p>A última configuração, portanto, consiste em adicionarmos a dependência do <a href="https://firebase.google.com/docs/ml-kit/android/recognize-text">Firebase Machine Learning Vision</a> ao nosso projeto Android. Para tanto, basta adicionarmos a linha 64 no arquivo android\app\build.gradle, conforme apresentado na Figura 14.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/929/1*RWq14fI8rcwgKRp6c9YcDg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iw3TPwVYTbKmEE4eBC9tOQ.png" /><figcaption>Figura 14. Adicionando a dependência do Firebase ML Vision no projeto Flutter/Android.</figcaption></figure><h3>4. Usando o Firebase Machine Learning</h3><p>Ufa! Tudo configurado! Agora, conforme disse Linus Torvalds,</p><blockquote>“Talk is cheap. Show me the code.”</blockquote><p>Portanto, vamos mostrar (e explicar) o código! No nosso arquivo main.dart, em específico dentro de nossa classe _HomePageState, vamos implementar os métodos pickImage(), readTextFromImage() e translate(). Como os próprios nomes já indicam (obrigado pela dica de limpeza, &quot;Uncle Bob&quot;), os métodos realizam, respectivamente, a captura de uma imagem usando a câmera do dispositivo, o retorno dos textos encontrados na imagem e a tradução destes textos para o português.</p><p>Na Figura 15 é apresentado o método pickImage , o qual utiliza-se da biblioteca image_picker e do método getImage() da class ImagePicker para acessar a câmera do dispositivo e retornar o arquivo contendo a imagem capturada. Ainda no método getImage(), podemos definir de onde virá a imagem (câmera ou galeria). Neste exemplo, utilizaremos apenas a câmera.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vT6sy3vs2hpCK60MCxH6tw.png" /><figcaption>Figura 15. Método para captura de uma imagem usando a câmera do dispositivo.</figcaption></figure><p>No método readTextFromImage , apresentado na Figura 16, é utilizado efetivamente o Firebase Machine Learning, em especial, a classe FirenaseVision (linha 40), a qual permite retornar uma instância da classe TextRecognizer, responsável por realizar o reconhecimento e retorno de textos em uma imagem (sendo esta transformada num objeto da classe FirebaseVisionImage, linha 38).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hNXBYIo7AuyiAn-l5Mx_Dg.png" /><figcaption>Figura 16. Método para realizar a captura dos textos disponíveis em uma imagem.</figcaption></figure><p>Para cumprir o objetivo do aplicativo, implementamos o métodotranslate() apresentado na Figura 17. A partir de um objeto da classe GoogleTranslator, invocamos o método translate() informando como parâmetros o texto que queremos traduzir e o idioma para o qual queremos que o texto seja traduzido (linha 47).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7d6Yw3vzGPxNiQE8cQIljA.png" /><figcaption>Figura 17. Método para realiar a tradução de um texto para português (pt).</figcaption></figure><p>Como podemos ver nos métodos anteriores, todos executam de maneira assíncrona e, portanto, utilizamos os recursos da linguagem Dart para aguardar (async/await) que tais métodos finalizem suas execuções antes de alterarmos o estado do <em>widget</em> com o texto traduzido (linhas 56–58).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UGqdee80HSstZSXUbA4j3A.png" /><figcaption>Figura 18. Método responsável por invocar, de maneira síncrona, os métodos anteriores.</figcaption></figure><p>Implementado todos os métodos, nos resta apenas alterar o método build, em específico o método onPressed do objeto FloatingActionButton, para que invoque o método translate ao ser pressionado.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HiV5Ibg_EbtkpZ4IxRpDKw.png" /><figcaption>Figura 19. Código do método build alterado para invocar o método translateTextImage.</figcaption></figure><h3>5. Executando o aplicativo</h3><p>Vamos aos testes! E nada melhor que utilizar um exemplo empreendedor, a tradução da capa do livro &quot;The Lean Startup&quot;, de Eric Ries, dado a mim pelo maior empreendedor que conheci na minha vida, meu amado pai, Rui Dezani (<em>in memorian</em>), cujo nome foi dado honrosamente ao Centro Incubador de Empresas da cidade de São José do Rio Preto, SP.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*KKidiBeCL0KXbObtdXIKoQ.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*QWbRS_F6qtBZoR4AtBDsxA.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*e1yiAVtgNufVxj5XOHW3Sw.jpeg" /><figcaption>Figura 20. Executando o aplicativo.</figcaption></figure><p>Como podemos ver nas telas apresentadas na Figura 20 (da esquerda para a direita), ao carregarmos o aplicativo temos o texto com uma mensagem padrão sendo exibida (&quot;Tire uma foto do texto que deseja traduzir&quot;). Ao tocarmos no FloatingActionButton, a câmera é aberta e, ao tirarmos a foto da capa do livro, o texto disponível na foto é obtido e traduzido usando os recursos do Firebase Machine Learning para, então, ser exibido ao usuário.</p><p>O projeto completo pode ser encontrado no meu repositório no <a href="https://github.com/henriquedezani/flutter-firebase-ml-ocr-translate">GitHub</a>, basta acessar o link abaixo.</p><p><a href="https://github.com/henriquedezani/flutter-firebase-ml-ocr-translate">henriquedezani/flutter-firebase-ml-ocr-translate</a></p><p>Antes de concluir, gostaria de indagar você, leitor, sobre as possibilidades de desenvolver projetos usando estas tecnologias. Pense bem e colabore deixando seu comentário com uma sugestão de aplicação prática.</p><p>Obrigado e até o próximo artigo!<br><strong>Prof. Dr. Henrique Dezani</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=55965d9cf491" width="1" height="1" alt=""><hr><p><a href="https://medium.com/henrique-dezani/flutter-e-firebase-machine-learning-na-pr%C3%A1tica-55965d9cf491">Flutter e Firebase Machine Learning na prática.</a> was originally published in <a href="https://medium.com/henrique-dezani">Henrique Dezani</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Criando uma aplicação web com Microsoft ASP.NET MVC e C#]]></title>
            <link>https://medium.com/henrique-dezani/criando-uma-aplica%C3%A7%C3%A3o-web-com-microsoft-asp-net-mvc-e-c-5c145554cfeb?source=rss-3e4ded46e720------2</link>
            <guid isPermaLink="false">https://medium.com/p/5c145554cfeb</guid>
            <category><![CDATA[programação-web]]></category>
            <category><![CDATA[azure]]></category>
            <category><![CDATA[visual-studio]]></category>
            <category><![CDATA[aspnet-mvc]]></category>
            <category><![CDATA[csharp]]></category>
            <dc:creator><![CDATA[Henrique Dezani]]></dc:creator>
            <pubDate>Tue, 20 Mar 2018 23:30:23 GMT</pubDate>
            <atom:updated>2019-08-24T11:12:22.938Z</atom:updated>
            <content:encoded><![CDATA[<p>Olá! Meu nome é Henrique Dezani, sou professor, doutor e trabalho com desenvolvimento <em>web</em> com .NET desde 2006. Já trabalhei em grandes projetos para a MetLife, Globo, Sony Entertainment entre outras grandes empresas. Sempre gostei de programar e para se ter uma ideia, eu iniciei na programação criando um jogo baseado em texto — <em>text-based game or interactive fiction</em>— aos 11 anos (1992) num computador IBM/AT com tela monocromática usando a linguagem Basic e instruções GOTO. De lá para cá muita coisa evoluiu, principalmente no que concerne a facilidade em desenvolver, compilar e publicar aplicações. O Framework .NET, no meu ver, juntamente com o IDE (<em>Integrated Development Environment</em>) Visual Studio, consistem em uma das tecnologias que trazem a maior produtividade nos aspectos relatados anteriormente.</p><p>Neste artigo eu apresento o passo a passo da criação de parte de um CRUD (Create, Read, Update, Delete) em ASP.NET MVC (<strong><em>M</em></strong><em>odel </em><strong><em>V</em></strong><em>iew </em><strong><em>C</em></strong><em>ontroller</em>) utilizando a linguagem de programação C# (C Sharp) e o banco de dados SQL Server. Ao final da leitura deste texto você estará apto a desenvolver uma aplicação com conexão ao banco de dados SQL Server utilizando a biblioteca ADO.NET e o IDE Visual Studio 2017 que realiza o cadastro e a consulta (CR) de uma tabela.</p><p>O Framework ASP.NET MVC tem sido muito utilizado no mercado e novos recursos são adicionados constantemente. Como um exemplo mais recente, temos o Microsoft Bot Framework, que permite a criacão de ChatBots utilizando a linguagem de programação C# e faz uso da Web API 2 do ASP.NET MVC.</p><h3>O projeto</h3><p>Tenha em mente que este artigo foi escrito com a proposta de fornecer um material didático para a criação de aplicações <em>web</em> utilizando o ASP.NET MVC. Portanto, nada como uma aplicação simples de exemplo para tratarmos do assunto.</p><p>O projeto a ser desenvolvido consiste em uma aplicação para armazenamento de, adivinhem só, tarefas (afazeres).</p><p>Para iniciarmos, vamos começar criando nosso banco de dados no SQL Server, conforme <em>script</em> exibido na Figura 1. O banco de dados terá o nome de BDContatoe conterá apenas 1 tabela, chamada Contato. Esta tabela possui 3 campos (colunas), quais sejam, IdContato, gerado automaticamente e que representa a chave primária (primary key), Nomee Email, sendo estes últimos obrigatórios e do tipo string.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0bb8d93c44222330ce6e41b130cba054/href">https://medium.com/media/0bb8d93c44222330ce6e41b130cba054/href</a></iframe><h3><strong>Desenvolvimento</strong></h3><h4><strong>1. Instalação do Visual Studio 2017 Community</strong></h4><blockquote>Quem já tem familiaridade com o Visual Studio, pular para o tópico 2!</blockquote><p>Para quem estiver começando o desenvolvimento e .NET, C# e Visual Studio agora, peço que faça o <em>download</em> do Visual Studio Community gratuitamente a partir deste link: <a href="https://www.visualstudio.com/vs/">https://www.visualstudio.com/vs/</a></p><p>Não explicarei o processo de instalação, mas consiste no tradicional NNF (Next, Next and Finish). O Visual Studio 2017 traz diversos recursos, mas precisaremos apenas do ASP.NET e suas dependências. Veja a Figura 2 do que devemos selecionar na instalação.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hkasm-Sr8HHRsjSBbCW2Pw.png" /><figcaption>Figura 2. Tela de instalação do Visual Studio 2017 com os componentes necessários para desenvolvimento <em>web</em>.</figcaption></figure><h4><strong>2. Criando um projeto de aplicação <em>web</em> com ASP.NET MVC.</strong></h4><p>Para criarmos um <strong>novo projeto</strong>, basta seguir o fluxo normal das aplicações do sistema operacional Windows. No Visual Studio, selecione na barra de menu superior a opção File e depois New Project. A tela apresentada na Figura 3 aparecerá.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*h6dttXz-vuvpe2B86w0vOg.png" /><figcaption>Figura 3. Tela do Visual Studio para criar um novo projeto</figcaption></figure><p>Nesta tela (Figura 3), basta selecionar o template da linguagem Visual C# Web, em seguidaASP.NET Web Application. Ao final desta tela você deverá entrar com o<strong> nome do projeto</strong>, o <strong>local</strong> onde deseja gravá-lo e o nome da <strong>solução</strong>. A solução nada mais é do que uma estrutura que permite organizar um ou mais projetos de uma maneira prática em termos de compartilhamento e manipulação de bibliotecas.</p><p>Para termos o mesmo padrão durante o desenvolvimento do projeto, coloque o nome do projeto como sendo ContatoWeb e o nome da solução como ContatoSolution .</p><p>Em seguida, ao clicar no botão OK, uma nova tela no Visual Studio se abrirá (Figura 4). Nesta tela, basta selecionar o template Vazio e logo abaixo a estrutura do projeto MVC.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CFFTWKr--c9oUs4vmM2Oww.png" /><figcaption>Figura 4. Tela do Visual Studio para escolha do modelo de projeto web ASP.NET</figcaption></figure><h4>3. Entendendo a estrutura do Framework ASP.NET MVC</h4><p>Ao finalizar a criação do projeto, accesse o Gerenciador de Soluções e veja a estrutura do projeto. Basicamente, o projeto ASP.NET MVC contempla três diretórios principais, quais sejam, Controllers, Models e Views, os quais serão discutidos nos tópicos que se seguem.</p><p>Na Figura 5 eu apresento o diagrama de classes do projeto. Dando um explicação bem simples, as classes criadas na pasta Models realizam o acesso ao banco de dados SQL Server, enquanto que as classes criadas na pasta Controllers atuam como intermediárias entre a visão (Views) do cliente — páginas HTML (<strong>H</strong>yper<strong>T</strong>ext <strong>M</strong>arkup <strong>L</strong>anguage)— e o modelo — Banco de Dados. São as classes Controller que desenvolvemos grande parte das validações e regras de negócio do sistema (não estamos considerando a aplicação de DDD — <strong><em>D</em></strong><em>omain </em><strong><em>D</em></strong><em>riven </em><strong><em>D</em></strong><em>esign</em>).</p><h4>4. Criando as classes (entidades) que representam as tabelas do banco de dados</h4><p>Uma vez que temos nosso banco de dados criado, precisamos criar as classes que a representem no sistema. Para tanto, basta clicarmos com o botão direito no diretório Models e selecionar as opções Adicionar → Classe. Na Figura 6 é apresentado o código da classe C#, chamada Contato, que representa a tabela Contato no nosso banco de dados.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9656f2654164106f373fb86f67336b31/href">https://medium.com/media/9656f2654164106f373fb86f67336b31/href</a></iframe><p>Analisando o código da Figura 6, conseguimos determinar que ela está dentro do namespace ContatoWeb.Models. Não é uma questão obrigatório, mas é uma boa prática, ter os namespaces relacionados aos nomes dos diretórios do projeto.</p><p>Dentro da classe temos três propriedades, quais sejam, IdContato (int), Nome (string) e Email (string). Esta estrutura representa o que chamamos de propriedades automáticas, ou seja, o encapsulamento destes campos é tratado automaticamente pelo <em>framework</em>, e o que precisamos fazer é simplesmente tratar estas propriedades como se fosse atributos (sem os métodos <em>get</em>/<em>set</em>). Veja como são utilizados nas linhas 14, 15 e 16 do código apresentado na Figura 7.</p><h4>5. Criando as classes Models (manipuladoras do banco de dados)</h4><p>Na Figura 7 eu apresento o código da classe ContatoModel , o qual contempla os métodos responsáveis por abrir e fechar a conexão com o banco de dados, assim como inserir (create) e listar (read) os registros da tabela Contato.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/42bb628e0822c9cf6a19c1b8053c81b8/href">https://medium.com/media/42bb628e0822c9cf6a19c1b8053c81b8/href</a></iframe><p>Como pode ser visto no código da Figura 7, a camada Model atua no acesso e manipulação das tabelas do banco de dados SQL Server. Para tanto, far-se-á necessário utilizar o namespace System.Data.SqlClient, que contém as classes necessárias para conexão (SqlConnection), consulta (SqlCommand) e retorno dos dados (SqlDataReader) do banco de dados SQL Server.</p><p>Na declaração da classe, implementamos a interface IDisposable que contém apenas um método público: Dispose. Este método é executado sempre que a classe é &quot;finalizada&quot;. Digo entre aspas pois, para realmente executar este método, é necessário utilizarmos a palavra chave using, como veremos mais adiante no artigo.</p><p>A ideia é que no construtor da classe realizemos a conexão com o banco de dados e no método Dispose realizemos o fechamento desta conexão. Na linha 9 temos declarado um campo privado do tipo SqlConnection. Este campo é quem controlará a conexão com o banco de dados e o chamamos de connection.</p><p>Na linha 14 instanciamos esta classe passando como parâmetro para o construtor uma <em>string</em> (declarada na linha 13 e que armazena a string de conexão com nosso banco de dados). Para efetivamente abrir uma conexão, utilizamos o método Open() do objeto connection (linha 15). Como é de se esperar, utilizamos o método Close() para fechar a conexão (linha 20, dentro do método Dispose).</p><p>Os métodos que realizam a inserção ou a consulta de dados na tabela são apresentados nas seções que seguem.</p><p><strong>5.1. Recuperando os dados armazenados na tabela do banco de dados.</strong></p><p>Na Figura 8eu apresento a implementação do método Read, que faz uso das classes SqlCommande SqlDataReader citadas anteriormente.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/44776eb125d57d5358057b20dc5e90e2/href">https://medium.com/media/44776eb125d57d5358057b20dc5e90e2/href</a></iframe><p>Na linha 3 é criada uma <em>collection</em> (Lista) de objetos da classe Contato. O objetivo do método é justamente retornar esta lista (linha 21) preenchida com objetos da classe Contato preenchidos com dados da tabela do banco de dados.</p><p>Na linha 5 temos a criação de um objeto da classe <strong>SqlCommand</strong>. Esta classe é responsável por executar comandos SQL no nosso banco de dados SQL Server. Para tanto, se faz necessário definir pelo menos duas de suas propriedades, quais sejam, Connection (linha 6), que indica por qual conexão com o banco de dados será executado o comando, e CommandText(linha 7), que é justamente o comando SQL a ser executado no banco de dados.</p><p>Como o objetivo deste método é retornar uma lista com informações do banco de dados, realizamos uma consulta (SELECT * FROM Contatos). A execução desta consulta SQL é feita na linha 9 e é armazenada num objeto da classe SqlDataReader. A execução do método ExecuteReader do objeto cmd nos retorna um cursor que permite percorrer o resultado do da consulta realizada. Para percorrer então o resultado, utilizando a estrutura de repetição while (linha 11).</p><p>Dentro desta estrutura de repetição, temos o objeto reader apontando (por isso ser um cursor) para um registro da tabela do nosso banco de dados, ou seja, se tivermos dois registros na tabela Contato, este laço será executado duas vezes e, a cada execução, retornará uma linha da tabela. Obtendo o registro da tabela, simplesmente criamos um objeto da classe Contato (linha 13) e definimos os valores de suas propriedades com os dados do cursor reader (linhas 14, 15 e 16). Não entrarei em detalhes neste artigo, mas o que precisamos entender é que uma tabela pode possuir campos (colunas) com diversos tipos de dados, mas para recuperamos temos apenas o objeto reader. Para resolver este impasse, utilizamos o polimorfismo . Fique ligado, em breve escreverei um artigo sobre como os <strong>Power Rangers</strong> entram nisso.</p><p>Dentro do laço, por fim, adicionamos o objeto da classe Contatona nossa Collection, a qual é retornada do método na linha 21.</p><p><strong>5.2. Criando, atualizando e apagando registros na tabela do banco de dados.</strong></p><p>Na Figura 9 eu apresento o método para criar registros na nossa tabela Contato do Banco de Dados.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bf2f81da7e7c7cf90b448ab16898d2d6/href">https://medium.com/media/bf2f81da7e7c7cf90b448ab16898d2d6/href</a></iframe><p>Comparado ao método Read (Figura 8), podemos ver que o método Create (Figura 9) é mais simples, pois não precisamos receber nada da base de dados, ou seja, estamos realizando uma manipulação e não consulta. Consequentemente, o método não tem retorno.</p><p>Em contrapartida, temos parâmetros que devem ser enviados pelo comando SQL (linhas 7 e 8), tais como o nome e o e-mail do contato. Mas e o IdContato? Pois bem, se nos atentarmos ao script SQL da Figura 1, verificamos que a chave primária é identity, ou seja, gerada automaticamente pelo SQL Server.</p><p>Na linha 5, o comando SQL possui duas variáveis que serão preenchidas em tempo de execução pelos valores informados nas linhas 7 e 8. Cada variável possui um apelido (alias), ou seja, @nome e @email. Isso é feito para evitarmos SQL Injection.</p><p>Nas Figura 10 e 11 eu apresento os métodos Update e Delete, respectivamente. Não serão tratados neste artigo, mas é fácil verificar que a implementação dos métodos que manipulam uma tabela no banco de dados segue em padrão.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2c98404fc3d2130464f5305239da1e67/href">https://medium.com/media/2c98404fc3d2130464f5305239da1e67/href</a></iframe><p>Apenas uma observação. Na Figura 10, verificamos que eu usei @id como nome do parâmetro, mas o valor foi da propriedade IdContato do objeto contato. Portanto, não precisamos ter o mesmo nome do parâmetro e o nome da propriedade, mas é uma boa prática para facilitar posteriores manutenções no código.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/531d3f300debce94470751db2abe447a/href">https://medium.com/media/531d3f300debce94470751db2abe447a/href</a></iframe><p>Com os códigos apresentados até aqui temos a classe ContatoModel pronta para ser utilizada em nosso projeto. Uma vantagem em separar o projeto em <strong>camadas</strong>, como feito aqui, é justamente a possibilidade de isolar suas implementações, ou seja, uma vez que temos a classe ContatoModel pronta, podemos manipular o banco de dados usando os métodos da classe sem ter que nos preocupar com suas implementações. Além disso, se num futuro desejarmos alterar a manipulação do banco de dados de ADO.NET para o Entity Framework, basta alterar apenas esta camada.</p><h4>6. Criando o Controller</h4><p>Uma vez que temos a camada Models pronta, trabalharemos com a classe Controller, a qual utilizará os métodos da classe Model para enviar ou recuperar dados do banco de dados para o usuário, a partir de uma interface desenvolvida em HTML (Views).</p><p>Para criar uma classe Controller basta clicar com o botão direito no diretório Controllers e selecionar a opção Adicionar → Controller. A tela exibida pelo Visual Studio dará a opção de selecionar o tipo de Controller. Trabalharemos neste artigo com a primeira opção: Controller MVC vazio.</p><p>Em seguida será perguntado o nome da classe. É importante notar que o Visual Studio deixa pronto para você editar apenas o prefixo, mantendo assim o sufixo Controller. Este é apenas um padrão do <em>framework</em>, mas acho interessante mantê-lo por questões de documentação. Para seguirmos o padrão do nosso projeto, coloque o nome desta classe de ContatoController.</p><p>Criada a classe, é possível reparar que o Visual Studio automaticamente criou um diretório chamado Contato dentro do diretório Views. Isso significa que cada Controller possui suas Views específicas. No nosso caso, no tópico 7, trabalharemos com duas Views, quais sejam, Index e Cadastro.</p><p>Na Figura 12 é apresentado o código gerado pelo Visual Studio seguindo as etapas anteriores. É importante ressaltar que a classe ContatoController herda da classe Controller(linha 7). Isto nos permite manipular as requisições HTTP (<strong>H</strong>yper<strong>T</strong>ext <strong>T</strong>ransfer <strong>P</strong>rotocol) com um alto nível de abstração, ou seja, ao invés de lidarmos com Request/Response e Get/Post, trabalhamos com invocação e retorno de métodos.</p><blockquote>É possível trabalharmos num baixo nível de abstração e, aliás, fazemos muito isso quando trabalhamos com Web APIs, mas foge do escopo deste artigo.</blockquote><p>Os métodos da classe ContatoController são chamados também de Action e têm como retorno uma ActionResult. Uma ActionResult retorna uma resposta para o cliente, seja ela uma View (que corresponde a uma página HTML, como no caso dos métodos Read (linha15) e Create (linha 22) ou um redirecionamento para uma Action como na linha 35.</p><p>As Actions, juntamente com os Controllers formam as URLs da aplicação. Por exemplo, se executarmos o projeto e digitarmos no navegador a URL http://localhost:1234/contato/create teremos o método Create (declarado na linha 20) executado. Se digitarmos a URL http://localhost:1234/contato/index teremos o método Index da linha 10 executado.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b87bfdfb2db8f86789b687785b6c2bea/href">https://medium.com/media/b87bfdfb2db8f86789b687785b6c2bea/href</a></iframe><p>Temos 3 métodos na classe ContatoController , quais sejam, Index, Create e Create. Espere aí! Dois métodos Create? Oras pois, sim! Retomando os conceitos de Orientação a Objeto, o que temos neste caso é uma sobrecarga de métodos, os quais se diferenciam pela quantidade ou tipo de parâmetros — neste caso, pela quantidade de parâmetros. Repare que na linha 20, a declaração do método Create não recebe parâmetros. Já na linha 26, a declaração do outro método Create recebe um objeto da classe FormCollection.</p><p>Em relação ao método Create, como é uma ação a ser executada pelo Controller, a sobrecarga não é suficiente para diferenciá-los. Portanto, o primeiro método Create tem o atributo [HttpGet] que indica que ele aceitará requisições por Get (por exemplo, quando chamado a partir de <em>links</em> ou executados ao digitar o caminho na barra de endereço do navegador). No segundo método (linha 25), tem-se o atributo [HttpPost] o qual indica que este método só será executado quando foi chamado a partir de uma requisição por Post (consideraremos que a única maneira de realizar uma requisição por Post é quando submetermos um formulário com o atributo method igual a post). Veremos as chamadas mais adiante no tópico 7 (Criando as Views).</p><h4>7. Criando as Views</h4><p>Certo, chegamos até este ponto e sabemos que ao solicitar a URL http://localhost:1234/contato/index teremos o método (Action) Index executado. Mas qual será a View? Ou seja, qual a página HTML será exibida. Vamos criá-las.</p><p>Clicando com o botão direito dentro das Actions o Visual Studio nos dá a opção Add View que realiza a criação da View. Esta View nada mais é do que uma página HTML. Bom, na verdade, é uma mistura de HTML e C# (daí a extensão ser .cshtml. Este junção consiste numa tecnologia chamada Razor.</p><p>Criando nossa primeira View (Index), temos o código apresentado na Figura 13. Um primeiro ponto a destacarmos é o código entre as linhas 1 e 3, que corresponde a um código C#. A instrução Layout=null simplesmente indica que não utilizaremos um LayoutPage (matéria de outro artigo).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5fa5b9778eeda33b9b0c01c7e5633dcb/href">https://medium.com/media/5fa5b9778eeda33b9b0c01c7e5633dcb/href</a></iframe><p>Porém, esta página ainda é estática e nosso objetivo é torná-la dinâmica a ponto de exibir e montar uma tabela com os dados enviados para ela (uma lista de objetos da classe Contato — linha 15 da Figura 12). Veja como é simples o código para tornar nossa página dinâmica (Figura 14).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2923dda9456b3127669b6bfaab51779a/href">https://medium.com/media/2923dda9456b3127669b6bfaab51779a/href</a></iframe><p>Na linha 1 agora temos a definição do modelo de dados que esta página receberá, ou seja, estamos indicando que ela receberá uma collection de objetos da classe Contato. Pronto. A partir de agora podemos utilizar a palavra reservada Model que conterá nossa collection List&lt;Contato&gt;.</p><p>Para percorrê-la, basta utilizarmos a instrução foreach da linguagem C#, mostrada na linha 15. Repare que criamos um laço que será executado de acordo com a quantida de objetos em nossa lista. Em cada execução do laço, um código html que representa uma linha da tabela será criada e conterá três colunas, quais seja, IdContato, Nome e Email.</p><p>Para concluirmos o projeto, temos a View Create.cshtml apresentada na Figura 15. O código apresenta um simples form, mas o mais importante é ressaltar os atributos action e method. Repare que o formulário submete os dados Nome e Email para a action Create, mas usando o método post. Portanto, será executado o segundo método Create que contém o atributo [HttpPost], sendo que o objeto form conterá estes dados (linhas 29 e 30 da classe ContatoController).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e35ecd7146c3280caefcce6d3d088ef7/href">https://medium.com/media/e35ecd7146c3280caefcce6d3d088ef7/href</a></iframe><p>Que bom, consegui! (Espero que esta seja sua resposta final). Mas veja o sistema, bonito, não é? Não. Como costumo dizer aos meus alunos, é funcional, mas nada que dê para mostrar e receber um elogio da tia ou primo. (Vó e mãe não contam, pois elas sempre dizem que está lindo tudo que fazemos rs). Piadas à parte, seria bom adicionar o clássico e famoso <strong>Bootstrap</strong> (CSS). Fica a dica!</p><h3><strong>Considerações Finais</strong></h3><p>É isso. Espero que tenha gostado do artigo e que este possa lhe auxiliar no desenvolvimento inicial do seu projeto em ASP.NET MVC. Preencha seu e-mail abaixo e fique sabendo de novos artigos em primeira mão.</p><p>Grande abraço e até o próximo artigo!<br>Prof. Dr. Henrique Dezani</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F5d0a71%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F5d0a71%2F&amp;image=https%3A%2F%2Fe.enpose.co%2F%3Fkey%3DdRXnS9Gplk%26w%3D700%26h%3D425%26url%3Dhttps%253A%252F%252Fupscri.be%252F5d0a71%252F%253Fenpose&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d54d33d48f8f4f5c4386de408aa6d1a/href">https://medium.com/media/5d54d33d48f8f4f5c4386de408aa6d1a/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5c145554cfeb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/henrique-dezani/criando-uma-aplica%C3%A7%C3%A3o-web-com-microsoft-asp-net-mvc-e-c-5c145554cfeb">Criando uma aplicação web com Microsoft ASP.NET MVC e C#</a> was originally published in <a href="https://medium.com/henrique-dezani">Henrique Dezani</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>