quarta-feira, 13 de dezembro de 2017

Convenções e padrões no desenvolvimento de software

Porque é importante respeitar as convenções e padrões no desenvolvimento de software ?

Tenho certeza que a grande maioria de nós, principalmente a galera de .Net (explicarei) já presenciou nomes de classe em lowercase, propriedades em uppercase, variáveis que iniciam com "o" (exemplo: var oPessoa = new Pessoa();) e outras coisas que até causam arrepios. Ocorre que grande parte dessas nomenclaturas foram herdadas de linguagens interpretadas como php ou asp, e infelizmente, pessoas que vieram dessas tecnologias, trouxeram esse costume e acabaram por cometer esses erros (muita gente não vai gostar de ler isso, mas tentarei ser o mais claro possível).

- Primeiro vou explicar o porque eu disse "principalmente a galera de .Net":

Java, diferente de .Net, não teve uma linguagem "antecessora". Ou seja, não existiu uma linguagem anterior (um ASPZÃO) para criar vícios nos desenvolvedores.
Por muito tempo, a comunidade Java se preocupou em estabelecer um padrão, definir uma convenção - https://www.devmedia.com.br/convencoes-de-codigo-java/23871 - para possíbilitar que outras pessoas possam colaborar com a grande quantidade de bibliotecas que eram criadas e distribuidas na internet.

Observando o mundo microsoft, sejá usando VB ou C#, é possível lembrar quando surgiu o .Net Framework. Muitas pessoas buscando treinamentos, lendo sites para conhecer esse tal de .Net Framework que prometia acabar de vez com o bom e velho ASP. Então, essa galera do ASP, entrou de cabeça no .Net - seja com VB ou C# -, e trouxeram com eles as "PROPRIEDADES", "nomes_de_classes", ou "oVariaveis" e tudo mais que eles estavam acostumados a ver e colocar em pratica naquele mundo muito louco. Naquela época, não existia preocupação com convenções. As linguagens eram interpretadas. Eu não disponibilizada minhas bibliotecas para a comunidade. Eu não "versionava" meu código (meu git ou tfs era a pasta de produção onde o IIS fazia a leitura dos arquivos rsrs). Então, por esses motivos e também por motivos particulares ou misticos, é comum encontrar softwares dentro do mundo Microsoft com nomenclaturas totalmente fora da convenção.

Alguém diz: "Blz, falou falou falou e não falou nada... Quem disse que essa tal de convenção ai é a correta ?"

Bom, obviamente eu não fui. Mas essa convenção, padrão ou seja lá como quiser chamar, foi extrair do .Net Framework. Ou seja, a Microsoft já possui um padrão, tudo que a comunidade de desenvolvedores fez, foi extrair, documentar e difundir esse conhecimento com o objetivo de fazer o que a galera de Java já faz por anos: Padronizar a forma como um código é escrito.

Lembro da frase de um antigo colega/líder/coordenador/gerente: "Eu quero olhar para esse código e não saber quem foi que escreveu!" (by F.M.).

Bom, antes que eu clique no publicar e não coloque aqui a convenção que tanto falei, segue o link: http://www.dofactory.com/reference/csharp-coding-standards.

Vale ressaltar que nem eu, nem esse site ai são os donos da verdade. Basta observar atentamente a nomenclatura dos métodos, propriedades, variáveis, constantes, variáveis de contexto, etc... que existem no Framework .Net ou na própria documentação da Microsoft. Fazendo isso, garantimos que o próximo que pegar nosso código, terá condições de entender e seguir o mesmo padrão.

Alguns benefícios de criar e mantar convenções:

  • A palavra padrão começa a fazer sentido.
  • O código pode facilmente ser mantido por qualquer um e não apenas pelo criador.
  • Fica simples saber quando estou olhando para uma propriedade, um método, ou uma variável.
  • Aumento de produtividade, pois não é necessário perder tempo tentando entender o que aquele código significa.
  • Minimiza o custo com suporte em uma transferência de propriedade.
  • Demonstra respeito para com o próximo.


Bom, acho que consegui explicar a importância de utilizar convenções e padrões no desenvolvimento de software. Se você não faz isso hoje, não tenha vergonha. Começe agora mesmo. :D

Ah, só pra não esquecer: http://www.dofactory.com/reference/csharp-coding-standards

Retirar um arquivo do publish no visual studio

Hoje aprendi: Como retirar um arquivo do publish no visual studio

O Visual Studio possui um recurso chamado "Publish", que permite configurar o destino de um código compilado para que esse código seja usado em uma publicação.

Uma aplicação, seja ela Asp.Net ou qualquer outra tecnologia, pode utilizar o recurso de publish do Visual Studio. Porém, nem todos os arquivos são arquivos necessários para a execução da aplicação.

Existe uma opção no publish que, se habilitada, gera apenas os arquivos necessários para executar a aplicação. No entanto, existem arquivos que, por motivos particulares, não queremos que sejam enviados para o destino. Um exemplo? Blz, lá vai:

Quero publicar em uma pasta física arquivos que posteriormente serão enviados para outra pasta no servidor de aplicação. Mas eu não quero que meu web.config vá junto pois no servidor de aplicação existe um web.config que é constantemente alterado pelo sysadmin. Então, para evitar que eu acabe por esquecer o web.config e ele seja copiado para o servidor de aplicação, posso configurar para que o web.config não seja copiado no publish.

Alguém: "Ta certo, mas como faço isso ?"

----- OBSERVAÇÃO -----
-- A informação abaixo é muito complexa, tente ler com bastante atenção --
-----

Com o projeto aberto no visual studio, botão direito no arquivo web.config > propriedades > na opção "build action" altere o valor de "content" para "none". PRONTO !!! O arquivo não será mais enviado para a pasta de destino quando utilizarem o publish xD.

Enfim, resolvi postar isso depois de descobrir que um colega passou 2 anos copiando um arquivo manualmente para a pasta de destino, pois em algum momento alguém configurou para "none" esse arquivo. rsrs

É isso :D

segunda-feira, 18 de setembro de 2017

Forms authentication não mantem autenticado após login

Hoje aprendi: Forms authentication não mantem autenticado após login

Se você está quebrando a cabeça pra entender o porque seu forms authentication está "deslogando" o usuário logo após o login, pode ser que eu consiga te ajudar.

Um projeto que estive trabalhando nos últimos meses me ofereceu alguns desafios, entre eles, o web forms. Meu primeiro contato com web forms foi em 2004, quando fiz um curso na IBTA de web forms com VB.Net :( rsrs.

O forms authentication permite jogar todo o controle de autenticação de um usuário, para o .Net, facilitando a vida do desenvolvedor. O site msdn diz: "Forms authentication permite você autenticar seus usuários utilizando seu código proprietário e então manter um token de autenticação em um cookie ou em uma URL de pagina. Forms authentication esta presente no ciclo de vida de paginas ASP.NET através da classe FormsAuthenticationModule. Você pode acessar as informações e capacidades de forms authentication através da classe FormsAuthentication." (Ou seja, o que eu disse antes, sem encher linguiça).

Referência: https://msdn.microsoft.com/pt-br/library/7t6b43z4.aspx

O Forms Authentication possui diversas configurações e não vou falar delas, a ideia aqui é explicar o problema e a solução, como se fosse a pergunta e a resposta com a flag verde no stackoverflow (e eu sei que você vai direto na flag verde).


<authentication mode="Forms">
   <forms name="NomeDoMeuFormsAuthentication" loginUrl="logon.aspx" protection="All" path="/" timeout="30" />
</authentication>



Quando nossa aplicação executa em um domínio que pertence apenas a nossa aplicação, não teríamos esse problema, porém, se você tem 2 ou mais aplicações no mesmo domínio, usando forms authentication, sem definir um atributo "name", a qualquer momento, quando você executar um FormsAuthentication.SignOut(), você fatalmente vai matar todas as suas aplicações autenticadas no mesmo domínio. Confuso ? vou criar um exemplo:

domínio: www.mimimi.com.br
aplicação A: www.mimimi.com.br/A (uma pasta "A" no IIS configurado como site dentro do site www.mimimi.com.br)
aplicação B: www.mimimi.com.br/B (uma pasta "B" no IIS configurado como site dentro do site www.mimimi.com.br)

Caso eu acesse a aplicação A, e por algum motivo eu execute qualquer pagina na aplicação B que possui um FormsAuthentication.SignOut(), vou matar a autenticação da aplicação A. Para que isso não ocorra, eu preciso definir um "name" para cada forms authentication de cada aplicação.

Algo como:

Aplicação A:
<authentication mode="Forms">
   <forms name="AppA" loginUrl="logon.aspx" protection="All" path="/" timeout="30" />
</authentication>


Aplicação B:
<authentication mode="Forms">
   <forms name="AppB" loginUrl="logon.aspx" protection="All" path="/" timeout="30" />
</authentication>

Assim, quando aplicação "B" executar um FormsAuthentication.SignOut(), vou apenas matar a autenticação da aplicação "B".


Algo aparentemente simples, mas que quando não estamos pensando nesse como a origem do problema, pode consumir um tempo bem grande em analise e depuração.


Agradeço ao meu amigo Diogo que sofreu por 3 dias seguidos em outro projeto. Quando expliquei pra ele o que estava acontecendo, ele imediatamente disse que imaginava o problema.

É isso, se você chegou até aqui e conseguiu resolver o mesmo problema, fico feliz :)

domingo, 13 de agosto de 2017

Criando componente reutilizável com JavaScriptResult do .Net MVC

Hoje aprendi: Como utilizar o JavaScriptResult do .Net MVC para entregar javascript no formato de componente

O JavaScriptResult, bem como o ActionResult, são formas de retornar informações através de uma action em um Controller no .Net MVC. Utilizei algumas vezes para algumas aplicações pontuais, até que fui questionado sobre como embedar um código criado por mim, dentro do site de um cliente. Bom, nesse ponto o problema não era como fazer, mas sim, qual a melhor forma dentro do cenário que proposto.

O que eu sabia:

  1. Poderia entregar JavaScript com o JavaScriptResult.
  2. Um componente possui código HTML.
  3. Um componente pode querer se comunicar com uma determinada API e entregar também esses dados "embedados".
  4. Lógicas de negócio necessitariam de resoluções do meu componente.
  5. O cliente precisaria passar parâmetros para meu componente.



Criei uma View que possui todo o código HTML (no _ViewStart removi meu layout, não quero injetar as tags <html><body><head> pois a aplicação cliente já possui) que quero entregar para a aplicação cliente, e no meu controller, duas Actions, uma que retorna minha View (apenas para testar, pois eu pego o html da view diretamente da view que retorna javascript) e outra que retorna um código JavaScript.

A view que retorna JavaScriptResult precisa formatar o html de modo que ele possa ser injetado, como javascript, em uma pagina HTML do cliente. Para isso, criei um método que vai encontrar no HTML cliente a posição onde o meu script foi adicionado. Então, eu coloco o script  que faz a busca pela posição, concatenado com o HTML do meu componente já formatado como string javascript para que seja renderizado corretamente no cliente.

Para fazer a injeção do HTML, usei a função abaixo:


private string Html2Js(string html) {

            return @"

                var scripts = document.getElementsByTagName('script');

                var item;

                for(var i = 0; i < scripts.length; i++)

                {
                    if(scripts[i].src.toLowerCase().indexOf('/boasvindas/ola') > 0)
                        item = scripts[i];
                }
                item.parentElement.insertAdjacentHTML('beforeend', '" + html.Replace("'","\"").Replace(Environment.NewLine, string.Empty) + @"');
            ";
        }

Ah, claro, não posso esquecer de comentar que precisei pegar o html da View e para isso, usei a outra função abaixo:

private string View2String(string vn, object m)
        {
            ViewData.Model = m;
            using (var sw = new StringWriter())
            {
                var result = ViewEngines.Engines.FindPartialView(ControllerContext, vn);
                var viewContext = new ViewContext(ControllerContext, result.View, ViewData, TempData, sw);
                result.View.Render(viewContext, sw);
                result.ViewEngine.ReleaseView(ControllerContext, result.View);

                return sw.GetStringBuilder().ToString();
            }
        }

A controller fica mais ou menos assim:













Claro que é valido retirar da controller e colocar em uma classe a parte as funções Html2Js e View2String.

E para testar esse componente, basta criar um arquivo HTML (simulando um cliente) com o conteúdo:

















<html>
   <head></head>
   <body>
      <h1> Vou carregar o componente logo abaixo: </h1>
      <div>
         <script src="http://localhost:54516/BoasVindas/ola/6"></script>
      </div>
   </body>
</html>


* localhost:54516 é a porta gerado pelo IIS Express.

O Código completo da solução está disponível em: https://github.com/rcelebrone/Componente-JavaScriptResult

quarta-feira, 2 de agosto de 2017

Autorização por token na WebApi

Hoje aprendi: Algumas alternativas com autorização por token na WebApi

O André Baltieri escreveu um artigo simples e bacana com a proposta de demonstrar como configurar uma WebAPI usando Bearer Authentication. Eu costumo usar esse artigo para pegar os pacotes que preciso instalar em um novo projeto WebApi que necessite de autorização via token. Enfim, no que refere-se a geração e utilização do token, entendo observo 4 abordagens. São elas:
  1. Sem nenhum tipo de restrição aos endpoints.
  2. Autorização com geração de token por usuário e senha.
  3. Autorização com geração de token por um "código de cliente"
  4. Autorização controlada por CORS.
1) Não preciso falar nada sobre a primeira abordagem, é basicamente um repositório de operações acessíveis por qualquer requisição, sem restrições. Exemplo: API de consulta de endereço por CEP.

2) A segunda possibilidade seria gerar um token através de um usuário e senha. Exemplo: Etapas de login em aplicativo móvel. Faço uma requisição de um token passando o usuário e senha que o usuário informou, se esses forem validos, gero um token que permite acesso a todos os métodos restritos da API para o aplicativo.

3) A terceira é bem parecida com a segunda, porém o cliente que está utilizando a API, não possui usuário e senha, por talvez não ter uma etapa de login, mas mesmo assim, quero garantir que apenas esse cliente vai usar minha API. Então eu gero um hash qualquer, coloco em algum lugar da aplicação (pode ser no arquivo de configuração) e quando o cliente solicitar o token, ao invés de pegar o usuário e senha, vou pegar o código do cliente (clientId usando a proposta no artigo do André Baltieri) e verificar no meu arquivo de configuração se o hash que estou recebendo no header é igual aos hashs que configurei para ter acesso. Caso o hash tenha acesso, ofereço o token e novamente os métodos restritos terão acesso quando a requisição possuir o token gerado no header.

4) A quarta possibilidade é bem simples também. Caso eu crie um API que será usada pelo domínio xpto.com.br, então basta configurar na própria API para permitir apenas esse domínio. Quando a restrição não é por domínio, geralmente usamos "*" para indicar que qualquer domínio pode ter acesso (e tratamos as restrições com as abordagens 2 e 3 mencionadas acima).


Certo, agora vem a pergunta: Não bastaria eu apenas verificar o usuário e senha ou no caso do código de cliente, comparar o que estou recebendo em cada requisição com o que está no meu arquivo de configuração ao invés de ter de gerar um token ?
A resposta: NÃO. Mas porque ???? :'(

É simples. Se o aplicativo ou site que vai usar minha API recebe um usuário e senha ou um código de cliente, significa que apenas ele deve possuir essa informação. Então, se eu passar esses dados em todas as requisições, ou pior, se esses dados são enviados por javascript por exemplo, estaremos entregando o código do cliente (hash) ou o usuário e senha para qualquer um que seja um pouco curioso (se é um site chamando uma operação via ajax, usando javascript, bastaria usar as ferramentas de desenvolvedor do browser e pronto, teriam acesso para usar a API). Agora, se eu entrego essas chaves, o site faz uma requisição do token (não faça isso via javascript, por favor, fatalmente você irá entregar seus dados. Faça isso no server) e obrigo a geração de token, eu garanto que todas as demais requisições serão autorizadas, e ainda manteremos os dados de usuário e senha ou código de cliente (hash) seguros mesmo quando usado em requisições do tipo GET, ou via javascript (por exemplo), pois o token é gerado de tempo em tempo, sempre muda. 

Vale lembrar que o token é configurado para expirar, então é importante sempre expirar o token pois se alguém, de alguma forma pegar esse token, ele não terá tempo de fazer alguma coisa com ele.

Enfim, é isso :) 


terça-feira, 1 de agosto de 2017

Criando pacote nupkg

Hoje aprendi: Como criar um pacote nupkg a partir de um projeto


Imaginemos um projeto (Class Library) que fornece algum tipo de funcionalidade e usamos a DLL dentro de outros projetos. Isso é comum, porém, quando atualizamos esse Class Library encontramos o problema: Como oferecer essa atualização aos projetos que usam essa DLL ?

A resposta para a pergunta acima é: Criar um pacote nupkg e oferecer em um repositório (pode ser uma pasta local).

Então, como fazer ?
- Faça download do nuget.exe (link para download) e coloque esse executável na sua unidade C:/
- Coloque na raiz do seu projeto (Class Library) um arquivo com a extensão .nuspec (pode ser qualquer nome).
- Coloque o conteúdo abaixo dentro do arquivo .nuspec:
<?xml version="1.0"?><package >  <metadata>    <id>namespace.do.projeto</id>    <version>1.0.0</version>    <authors>Nome do autor</authors>    <owners>Nome do proprietário</owners>    <requireLicenseAcceptance>false</requireLicenseAcceptance>    <description>Descrição do que o projeto se propõe a fazer</description>    <releaseNotes>Informação sobre essa versão</releaseNotes>    <copyright>Copyright 2017</copyright>    <tags>nuspec teste repositório</tags>    <dependencies>      <dependency id="biblioteca.que.minha.class.library.usa" version="1.00" />    </dependencies>  </metadata></package>

- Salve o arquivo e certifique-se de deixar a codificação do arquivo como UTF-8 (assim você evita problemas com acentos).
- Abra o prompt de comando e execute os comandos abaixo:
(em qualquer diretório) cd c:/
(em diretório c:/) nuget.exe pack "C:\pasta\do\seu\projeto\nome.da.solution" 
"C:\pasta\do\seu\projeto\nome.da.solution" (é nesse mesmo diretório que seu arquivo .nuspec deve estar)

- Na unidade C:/ será gerado um arquivo .nupkg, copie esse arquivo e cole no diretório que você quer que seja seu repositório. Por exemplo: "C:/nuget_repo/"
- Coloque o endereço "C:/nuget_repo/" como mais uma fonte de pacotes no nuget (no Nuget Package Manager da sua IDE)

segunda-feira, 31 de julho de 2017

Output cache no .Net MVC

Hoje aprendi: Possibilidades com output cache do .Net MVC


O OutputCache, na verdade já utilizei, mas como nunca escrevi sobre e recentemente utilizei no TCC da pós, resolvi escrever.

OutputCache é uma classe do namespace System.Web.Mvc (sim, não podemos usar na Web Api, mas nada que isso não resolva).  Basicamente a proposta é permitir que possamos configurar um cache para um determinado Action da nossa Controller. 

Mais ou menos isso:









Entre as diferentes configurações que podemos usar está o Duration, que recebe o valor da duração do cache em segundos  (após esse tempo o Action executa novamente e atualiza novamente o cache) ou o Location que recebe um enumerador com algumas configurações para indicar onde pretendemos gerar o cache (Client, Server, None, etc...). Existem outras configurações, mas para aplicações corporativas, é basicamente isso que usamos.

Quando habilitamos o cache em uma Action, com as configurações da imagem apresentada no post, estamos garantindo que dentro de 3600 segundos (uma hora), o código que está dentro do "{" e "}" não será reprocessado para retornar ao client. Quando a requisição chegar (e o cache estiver valido), o cliente imediatamente receberá os dados armazenados no cache por alguma requisição anterior (dentro do período de 3600 segundos).

domingo, 30 de julho de 2017

Cache em web api

Hoje aprendi: Cache em Web Api usando Memory Cache


Eu estava buscando algo pra representar no meu TCC como uma solução de cache para a minha API. Sabemos que OutputCache pertence ao namespace System.Web.Mvc, portanto, não podemos trabalhar com ele na Web Api. Então me veio a pergunta: O que eu posso usar para aplicar um cache nas operações da minha web api ?

Foi então que encontrei o artigo do Renato Groffe sobre o novo mecanismo de cache do Asp.Net 5 e resolvi testar para mencionar no TCC.

Abri o Visual Studio e criei uma POC simples para entender o comportamento do MemoryCache (que pertence ao namespace System.Runtime.Caching). A POC ficou assim:






Então, criamos um método para configurar o cache utilizando como referencia o MemoryCache.Default. A partir dele configuramos um tempo para expirar o cache, adicionamos os dados que queremos cachear no value do AddOrGetExisting() e retornamos o valor desse método (que é basicamente o que armazenamos em uma execução anterior).

É bem bacana e olhando para os sistemas que desenvolvemos diariamente, certamente podemos observar várias situações onde cabe um cache. Eu curti :)

terça-feira, 21 de fevereiro de 2017

Pronoo

O aplicativo Pronoo oferece ações para ouvir a palavra e validar a pronúncia. A medida que o usuário acerta a pronúncia, o aplicativo avança para a próxima palavra.
A ideia do aplicativo surgiu ao observar a quantidade de aplicativos e sites que oferecem cursos e treinamentos do idioma inglês, porém, esses não permitem que o usuário possa validar a pronúncia.


Tecnologias: Java, Google Speech API