C#: evitando a Injeção de SQL

A Injeção de SQL, ou em inglês SQL Injection, é uma vulnerabilidade que permite que algum usuário malicioso possa executar uma instrução em SQL dentro da aplicação, aproveitando uma brecha em uma consulta que permita acesso ao banco de dados.

Para demonstrar um exemplo desta vulnerabilidade, vamos criar um banco de dados de vendas, onde temos nossa tabela de usuários com alguns informações.

Abra o Visual Studio Code, e crie uma pasta chamada EvitandoAInjecaoDeSQL, e dentro dela outra chamada src. Em EvitandoAInjecaoDeSQL crie uma solução usando o comando dotnet new sln e logo em seguida abra a pasta src, adicione e logo abra um nova pasta chamada EvitandoAInjecaoDeSQL.Web e adicione um projeto do tipo MVC usando o comando dotnet new mvc, volte até a pasta EvitandoAInjecaoDeSQL e adicone o projeto na solução usando o comando  dotnet sln add .\src\EvitandoAInjecaoDeSQL.Web\EvitandoAInjecaoDeSQL.Web.csproj.

Adicione um controller na pasta Controllers do projeto de MVC chamado ContaController.cs e uma view chamada Login.cshtml na pasta Views/Conta.

A tela de login deve ser semelhante a esta, após abrir o site e digitar uma senha válida:

O nosso site está funcionando, então agora vamos aplicar o SQL Injection para verificar a vulnerabilidade. Como vimos, o campo usuário e senha só efetua login se for digitado um nome de usuário e uma senha correta. Mas vamos tentar burlar isto.

Para entdenr o que acontece no lado do banco de dados ao digitar o usuário e senha da captura de tela, vamos analisar a intrução SQL montada pelo aplicativo:

Se executarmos a instrução acima no SQL Server, temos o resultado 1, que é a informação que permite que o sistema permita o acesso.

Mas esta instrução é facilmente alterada usando alguns caracteres de ‘ (apóstrofo), fazendo a consulta ficar assim:

Que retorna um valor positivo, mesmo sem informar a senha.

Mas como isto é possível sem editar o SQL que está no código? Simples, pois a forma a instrução foi montada, permite que seja alterada, pois o SELECT é uma concatenação dos campos que são enviados no post e a o corpo da instrução, o C# não sabe o que é filtro e o que é comando de banco, ele monta primeiro uma string e depois executa no banco. Sendo assim, vamos recriar esta consulta direto no campo de senha.

Antes, tente digitar uma senha errada, para conferir se formulário está funcionando e acessando os dados corretamente.

Agora vamos explorar a vulnerabilidades, digitando no campo de senha ‘ OR ‘1’ = ‘1 e clique em login.

E acabamos de ser invadidos por uma falha bem simples no site, pois é possivel “editar” a instrução SQL antes de enviar. Este tipo de falha, pode ser tão grave que é até pode permitir acessar e alterar informações do próprio sistema operacional, dependendo da configuração do banco de dados.

Mas como consertamos este caso específico? A solução a seguir vai resolver este tipo de abertura, mas há outros tipos de falahas que podem precisar uma solução mais avançada. O que vamos fazer é passar parâmetros para o banco de dados em vez de montar todo o sql de uma vez, para isso, em vez de usar uma concatenação, mas nomer estes dados usando um @ (arroba antes) antes, então, para isto, vou comentar o código vulnerável do arquivo ContaController.cs e adicionar a forma mais segura, como segue:

Com isto, temos um código mais seguro. Outra solução, seria usar frameworks ORM, como Entity Framework ou NHibernate.

O projeto completo está disponível no meu GitHub:

https://github.com/tiagopariz/EvitandoAInjecaoDeSQL

Obrigado e um bom dia a todos.

 

Entity Framework: migrations com vários projetos e bancos de dados

Quando trabalhamos com soluções grandes, onde há vários projetos e cada um tem sua própria base de dados, assim como seu próprio versionamento usando Migrations do Entity Framework, fica meio complicado ficar alterando o Set as startup project e o Default Project na janela do Package Manager Console. Então, o ideal é apontar os projetos de configuração e dados na mesma linha de comando do Add-Migration e Update-Database.

Atualizando o banco de dados

Quando abrimos uma projeto que já tem migrations, precisamos atualizar o banco de dados, e para isso usamos o comando Update-Database. Mas podemos ser mais específico, e não precisar escolher nada em tela para que ele saiba onde achar a Connection String e Contexto, usando o comando abaixo.

Update-Database

Este comando atualiza o banco de dados com a ultima versão das migrations registradas, assim como roda algum Seed que pode popular tabelas.

-ProjectName

Nome do projeto onde está a configuração das entidades que representam os objetos do banco de dados, ou os DbSets.

-StartUpProjectName

O projeto que contém a Connection String para conexão com o banco de dados.

-ConfigurationTypeName

Nome completo, incluindo as namespaces, da entidade de configuração das migrations. Este arquivo é aquele que é gerado automaticamente ao usar o comando Enable-Migrations para ativar as migrações.

-Verbose

Este parâmetro exibe na tela todas as alterações efetuadas, assim como configurações definidas nos parâmetros anteriores.

Adicionando uma nova migração

Após atualizar o banco de dados, fazer as alterações nos objetos de domínio, precisamos adicionar a migração para depois enviar ao banco de dados as alterações versionadas, e novamente, é preciso que não precisemos definir o projeto de inicialização e dados. Para isso, use o comando a seguir:

Além dos parâmetros -ProjectName, -StartUpProjectName e -ConfigurationTypeName que já foram explicados no tópico anterior, precisamos incluir o parâmetro -Name e definir um nome que identifique qual alteração será feita no banco de dados.

Após adicionar a migration, só é preciso digitar o comando Update-Database com os parâmetros corretos.

VB.NET MVC: traduzindo do C# as aulas do Cleyton Ferrari

Cleyton Ferrari foi um dos primeiros profissionais de desenvolvimento C# brasileiros que fez um curso bem estruturado sobre MVC e Entity Framework, explicando nos detalhes como funcionava cada elemento, e melhor, tudo gratuito no Youtube.

Na época eu trabalhava com VB.NET, e por isso eu precisei traduzir o projeto didático dele para a linguagem que eu usava. Foi uma tarefa com dois ganhos, o primeiro que serviu para eu treinar meu C# que ainda era bem básico e segundo para entender a fundo o conceito do MVC e ORM com Entity Framework.

Não havia me preocupado em criar um post em 2013, e mal sabia usar o GitHub, mas guardei os fontes lá, e eles existem até hoje, por isso resolvi escrever para registrar isso aqui. Mas antes de entrar no meu repositório você quiser conferir os cursos dele, que apesar de ser feito para o ASP.NET MVC 3 ainda é bem válido:

E acesse aqui os projetos traduzido para VB.NET:

https://github.com/tiagopariz/CleytonFerrari

 

OpenCover: analisando e automatizando a cobertura de código

Cobertura de código é essencial para sabermos o quanto estamos investindo na qualidade do nosso projeto. Para isso, até temos recursos nativos na IDE do Visual Studio, mas apenas na edição Enterprise. Mas nem tudo está perdido para quem não tem acesso à edições “premium” do VS! Podemos substituir tranquilamente pelo OpenCover, que atende a este necessidade com grande eficiência e elegância. E isso veremos no projeto de exemplo que iremos montar com o Visual Studio 2017 e o NUnit.

Observação: o OpenCover atende outras plataformas de testes, inclusive a nativa da Microsoft, irei o Usar o NUnit apenas por escolha própria, fique a vontade para integrar com a ferramente que convir.

Crie a solução dos projetos

Crie uma solução vazia chamada CodeCoverage, e inclua três Solution Folders chamadas Domain, Presentation e Tests. na pasta Tests, inclua mais duas subpastas chamadas Domain e Presentation, que serão os testes específicos de cada camada.

Projeto de domínio

Crie um projeto do tipo Class Library chamado CodeCoverage.Domain dentro da pasta Domain, e dentro do projeto inclua outra pasta chamada Entities. Nesta pasta inclua três classes chamadas State, City e Person, pois estas classes que serão analisadas pelo OpenCover, afim de gerar um relatório com o percentual de cobertura por testes unitários. A seguir o código de cada uma delas:

Classe de estados

Classe de cidades

Classe de pessoas

Projeto de Console

O projeto de console, será a nossa camada de apresentação, onde vamos trabalhar com DTOs, que são representações dos dados das nossas classes de domínio. Para isso, na pasta Presentation da solução, adicione um projeto do tipo Console Application chamado CodeCoverage.Prompt, e dentro do projeto inclua um pasta chamada Dto. Onde residirão as 3 classes de dados que serão a StateDto, CityDto e a PersonDto, como segue:

DTO de estado

DTO de cidades

DTO de pessoa

Edite a classe Program.cs e crie o método  que faz os mapeamento entre o Domínio e DTO e o código que exibe os dados em tela.

Observação: não é intenção deste artigo explicar como funciona processos de mapeamentos entre entidades de domínio, DTOs e ViewModels. Mas fica a dica para você procurar na internet qual o funcionamento de um AutoMapper, por exemplo.

Testes

Expanda a pasta de solução Tests e dentro da pasta Domain adicione um projeto do tipo Unit Test Project chamado CodeCoverage.Domain.Tests.

Neste projeto, inclua uma pasta chamada Entities, e dentro dela vamos incluir duas classes de testes, mas antes é preciso instalar o pacote NUnit, para isso abra o Package Manager Console selecione o projeto de testes do domínio e digite:

Adicione uma referência para o projeto de domínio, para que os testes possam acessar as entidades. Então adicione as classes de testes na pasta Entities.

Testes da classe de estado

Testes da classe de pessoa

Adicione um outro projeto do tipo Unit Test Project chamado CodeCoverage.Prompt.Tests e adicione uma referência do projeto CodeCoverage.Prompt e instale o pacote do NUnit também.

Crie uma pasta chamada Dto, e dentro dela inclua uma classe de testes chamada PersonDtoTests para pessoas.

Usando o Cake

Abra o Powershell, e se posicione na pasta da solução, e logo após digite o comando para instalar o pacote que compila e executa o script do Cake:

Ainda na pasta raiz da solução, crie um novo arquivo chamado build.cake e crie também a pasta docs/testsResults/Reports, que será onde ficará os resultados dos testes.

Dica: você pode adicionar o arquivo build.cake à solução, para que ele faça parte do projeto, mas é muito mais produtivo usar o Visual Studio Code e a extensão do Cake, conforme expliquei neste artigo.

Volte ao Powershell e digite o comando .\build.ps1 para executar o script do Cake.

Após a execução do script, o Report Generator irá compilar os arquivos xml do OpenCover e gerar uma visualização mais amigável e detalhada e ainda abrir um sumário no seu navegador padrão, incluind um histório de cobertura.

.gitignore

Se você está usando o arquivo .gitignore padrão do Visual Studio – aquele que é fornecido, por exemplo, pelo GitHub ou Visual Studio Online – será preciso alterar para que ele ignore os arquivos compilados do Cake e não suba para o repositório do GitHub. Para isso encontre o trecho a seguir:

E descomente as duas últimas linhas.

Pronto, agora podemos acompanhar a evolução dos testes de nosso aplicativo de forma elegante e segura.

Até a próxima e se quiser, acesse o projeto completo em meu GitHub:

https://github.com/tiagopariz/CodeCoverage

Cake: automatizando tarefas

O Cake é um automatizador de tarefas construído sobre o compilador do C# e de fácil configuração.

Instalando o Cake

Para usar o Cake, precisamos baixar os scripts de automação que vem todos em um arquivo chamado build.ps1 que roda no Powershell. Para isso, abra o Powershell, crie uma pasta chamada CakeAutomation.

Com a pasta criado, execute o comando para baixar o pacote com as configurações.

Pronto, o ambiente está configurado, agora precisamos de um projeto para automatizar.

Crie uma aplicação de exemplo

Eu tenho um post que ensina como criar uma aplicação console com o Visual Studio Code, vamos usar este exemplo para automatizar uma build:

Visual Studio Code: como criar uma aplicação console em C#

Crie o script de build da aplicação com o Cake

Na raiz do projeto, inclua uma arquivo chamado build.cake, que será onde residirá todo o código de automação. Edite o arquivo conforme segue:

Agora o script está pronto para ser rodado, para isso, é preciso que você esteja na raiz do projeto, via powershell digite o comando a seguir:

Site oficial

https://cakebuild.net/

Extensão para VS Code:

https://marketplace.visualstudio.com/items?itemName=cake-build.cake-vscode

Repositório no GitHub:

https://github.com/tiagopariz/CakeAutomation

C#: Using e Dispose

Não vejo muitos softwares usando em seu código, pelo menos da maneira correta, o bloco using em conjunto método Dispose da interface IDisposable() da maneira correta. Mas vou mostrar em um exemplo bem simples como estes dois recursos podem ser poderosos para manter uma aplicação enxuta e performática.

Para começar, vamos criar uma solução chamada UsingAndDispose e incluir dois projetos, um projeto de domínio do tipo Class Library chamado UsingAndDispose.Domain e outro do tipo Console Application chamado UsingAndDispose.Prompt.

No projeto de domínio, vamos incluir uma classe chamada TxtFile, que recebe dois parâmetros via construtor, nome do arquivo e pasta, e com eles alimenta uma propriedade que retorna o caminho completo. Incluiremos também um método que efetuará o fechamento do arquivo após a leitura e limpará a memória, mas neste caso vamos apenas escrever um frase na tela do console.

Crie uma classe chamada TxtFile e defina uma herança da interface IDisposable, que exigirá a implementação do método Dispose, que chamará o método Close().

Obs.: Não vamos entrar na complexidade da lógica de leitura de um arquivo de texto de fato, mas apenas criar um classe que poderia implementá-la, o importante é entender o mecanismo do bloco using.

Então, no projeto de console, altere a classe Program.cs, incluindo um bloco using, conforme o código a seguir, e faça uma referência ao projeto de domínio para acessar a classe TxtFile.

Ao executar o código acima, percebemos que a mensagem do método Close é exibida em tela, mas o curioso que em nenhum momento o chamamos diretamente. Isso acontece porque a classe TxtFile implementa a interface IDisposable, e quando o using recebe objetos que são implementados a partir desta interface, automaticamente é chamado o método Dispose() ao fechar o bloco. E neste caso, o método Dispose() foi implementado com uma chamada ao método Close().

Acesse o projeto completo no meu GitHub:

https://github.com/tiagopariz/UsingAndDispose

 

 

Visual Studio Code: como criar uma aplicação console em C#

O Visual Studio Code é o novo editor de código open-source da Microsoft, multiplataforma, que já funciona no Windows, Linux e Mac. Com foco no novo .NET Core, que também é um framework totalmente open-source. Porém, por mais simples que pareça, programar no VS Code é consideravelmente diferente do que programar no famigerado Visual Studio.

Requisitos

O projeto de console

Abra o Visual Studio Code, clique no menu View, e em seguida em Integrated Terminal (CTRL + ‘). No terminal, crie uma pasta usando o comando md chamada ConsoleApplicationVSCode (podem usar o explorer do Windows sem problemas).

No menu File, clique em Open folder, e selecione a pasta que acabamos de criar.

Na janela do terminal, posicione na pasta criada e digite o comando dotnet new console.

Abra o arquivo Program.cs.

Edite a classe Program.cs conforme o código a seguir:

Clique no menu Debug, e em seguida em Start Debugging (F5), e então teremos nossa aplicação console funcionando!

Este tutorial básico tem o objetivo de “quebrar o gelo” para começar a usar o VS Code, e também demonstrar que este editor é tão simples quando os seus antecessores, além do mais, em conjunto com as extensões corretas, pode virar uma poderosa ferramenta de trabalho!

Acesso o código fonte no meu GitHub:

https://github.com/tiagopariz/ConsoleApplicationVSCode

 

C# with Patterns: Specification

Muitas vezes precisamos abstrair características complexas, tentando simplificar uma consulta Linq para um campo que retorne apenas true ou false, pois isto é muito útil, principalmente quando usamos Entity Framework. O padrão de comportamento especificação busca tornar características, que muitas vezes complexas, em algo mais simples, legível, reusável e de fácil manutenção, com uma abordagem mais elegante.

Além de auxiliar na criação de consulta, Specification pode ser bastante útil em validações, onde uma entidade de domínio precise checar uma série de informações e retornar se ela satisfaz um cenário válido para alguma finalidade específica ou até mesmo persistir os dados no banco. Em resumo, Specification é a união de regras de negócios e expressões boolianas.

Projeto de exemplo

O projeto de exemplo mostra dois usos da abordagem: uma para definir entidades com características específicas e outra para validar entidades, que pode usado juntamente com notificações e eventos. Para isso crie uma solução chamada Specification, e adicione um projeto do tipo Class Library, chamado Specification.Domain.

A interface ISpecification<T> que define o contrato de implementação do método IsSatisfiedBy() e que recebe a especificação baseada em regras de negócio, que são geradas a partir dos métodos And(), AndNot(), Or(), OrNot() e Not() ou uma expresão Linq.

Crie uma pasta chamada Specifications no projeto de domínio, e dentro dela inclua a classe CompositeSpecification, que será a base para as especificações, implementando todos os métodos da interface anterior.

Com a classe base criada, podemos criar as classes de operadores para definir a regra de negócio, que irá retornar uma resposta true ou false. Para isso, adicione as classes a seguir na pasta Specifications:

No projeto de domínio, crie duas pastas chamada Entities e ValueObjects. E em ValueObjects inclua uma classe base para os objetos de valor chamada ValueObject e dentro de Entities inclua uma classe base para as entidades chamada Entity. Estas duas classes terão as propriedades e métodos básicos para as especificações de validação e uma função IsValid que retornará true se os dados preenchidos atenderem os requisitos.

Na pasta ValueObjects teremos uma classe de Email que herda de ValueObject, e na pasta de Entities as classes Category e Person e ambas herdam de Entity.

Neste ponto, a propriedade ValidSpecification ainda não possui suas especificaçãos que validam pessoa e o e-mail, e para isso temos que criar as classes com as regras de negócio.

Entre na pasta Specification, e dentro dela crie uma pasta chamada ValueObjects e neste diretório inclua uma classe chamada EmailValidSpecification que herda de CompositeSpecification.

Na pasta Entities de Specification, inclua uma classe chamada PersonNameValidSpecification, que irá validar o nome da pessoa.

Com as especificação de validação de e-mail e de nome prontas, podemos adicionar uma especificação que irá validar a pessoa como um todo, e para isso inclua uma classe chamada PersonValidSpecification na pasta Entities de Specifications.

Ainda temos um especificação para definir se uma pessoa é cliente, que pode ser usada em filtros de listas baseadas em Linq, portanto inclua o objeto PersonCustomerSpecification na pasta Entities de Specifications.

Projeto de Apresentação

Crie um projeto do tipo Class Library, chamado Specification.Domain, para que, via console, testarmos algumas formas de usar as especificações. E então, no método Main da classe Program, crie uma lista de pessoas através de uma variável do tipo List.

A seguir vamos listar apenas os clientes, usando a especificação PersonCustomerSpecification.

Neste outro exemplo, retornarmos todas as pessoas que são parceiras, usando uma expressão Linq:

A seguir é usada uma especificação que filtra apenas entidades válidas usando a especificação pronta, mas esta operação pode ser feita também chamando o método IsValid da própria entidade.

Toda a classe Program pode ser vista a seguir, com outros exemplos:

E aqui temos a saída completa do console.

Conclusão

Specification é um padrão bastante flexível, tornando as regras de negócio do domínio mais claras. Entretanto, as validações podem ser simplificadas, usando pacotes de terceiros, como por exemplo o Flunt, que une esta abordagem com a Domain Notification, e pode residir em uma camada transversal do projeto.

O projeto completo pode ser baixado no GitHub:

https://github.com/tiagopariz/Specification

Referências

C# with Patterns: Notification

Segundo Martin Fowler, Notificação é um objeto que coleta dados sobre erros e outras informações na camada de domínio e que comunica com as outras camadas, principalmente com a camada de apresentação.

O padrão Notification, ou notificação, é uma solução elegante para tratar erros de sistema desnecessários, pois exceção, além de causar uma parada abrupta na execução de todo o programa, tem um custo muito alto para o processador. Por isso, usando uma lista de notificações é possível coletar os problemas previsíveis, listar, classificar e informar às outras camadas, ou até mesmo ao usuário, de uma só vez sobre todos os problemas que ele precisa corrigir antes de continuar.

A testabilidade do código também aumenta, pois é possível definir erros, alertas e mensagens padrões para determinadas situações sem lançar exceções, ou seja, agiliza o teste e fica muito mais claro o que o sistema espera de entrada. Ainda é possível combinar esta abordagem com outros padrões, como Specification e Design By Contract e criar um tratamento poderoso e profissional de validações.

O Artigo de Martin Fowler

O artigo original sobre Notification foi escrito em 2004, e faz parte do livro Patterns of Enterprise Application Architecture de 2003, e nele, Fowler até demonstra como usar o padrão usando C# em uma aplicação windows, mas para que fosse mais fácil entender hoje, eu atualizei a sintaxe usando C# 7.0 e desenvolvi alguns métodos que ele não incluiu no artigo, portanto, se você quiser acessar é só entrar no meu repositório Notification by Martin Fowler do GitHub e conferir a abordagem descrita por ele em uma aplicação console.

O Flunt e o Design By Contract de André Baltieri

André Baltieri, MVP da Microsoft, desenvolveu um pacote Nugget, chamado originalmente de Fluent Validator, no qual tive o prazer de contribuir, e que mais tarde foi rebatizado de Flunt. O Flunt é um sistema poderoso e extensível de validação e notificações em domínios, reduzindo “Ifs” e Testes, contribuindo na otimização do tempo,  podendo assim focar na codificação e na regra de negócio do seu domínio do projeto.

Para conhecer os detalhes deste pacote fenomenal e seu código fonte, é só ler o artigo Design By Contracts e também assistir os vídeos do canal dele. Posso garantir que será de grande proveito!

O Meu Projeto de Domain Notification

É possível usar as notificações de um modo simples, apenas para atender um necessidade específica, criando apenas uma lista de mensagens, mas este padrão é poderoso o suficiente para que seja usado em domínios complexos, e combinado com outras abordagens. O projeto que desenvolvi tem um nível de complexidade médio, por este motivo já indiquei o Flunt, pois é uma forma de usar o conceito para validações com o mínimo de esforço e máxima confiabilidade, e assim já terá grandes ganhos, como a redução do uso de exceções e Ifs. Mas se você é como eu, que gostaria de usar ao máximo o padrão e ter controle sobre todo o seu funcionamento, vai ver como desenvolver e usar neste exemplo prático.

Domain Driven Design – DDD

Quase todos os meus projetos são desenvolvidos usando a abordagem de arquitetura DDD, ou seja, quase sempre terá um projeto focado no domínio, assim como o uso de objetos de valor e pelo menos as camadas de domínio, aplicação e apresentação. Se você não faz ideia do que estou falando, não há problemas, é possível entender este artigo mesmo assim, mas se quiser saber mais sobre desenvolvimento dirigido ao domínio, segue a indicação de um excelente vídeo do Eduardo Pires, MVP da Microsoft.

A solução

Abra o Visual Studio, crie uma solução vazia chamada DomainNotification, inclua três Solutions folder chamadas Domain, Application e Presentation.

Na pasta Domain inclua um projeto do tipo Class Library chamado DomainNotification.Domain, na pasta Application inclua um projeto do tipo Class Library chamado DomainNotification.Application e finalmente na pasta Presentation inclua um projeto do tipo Console application chamado DomainNotification.Prompt e defina como Set as StartUp project. A estrutura deve parecer como a imagem a seguir.

Projeto de Domínio

O projeto de domínio será onde residirão as entidades principais, assim como suas classes bases abstratas, também conhecidas como camada de Supertypes. Mas vamos começar criando as estruturas e classes de notificação, que estarão nesta camada.

No projeto de domínio, inclua uma pasta chamada Interfaces, e dentro desta pasta, outra chamada Notifications. Em Notifications, inclua uma interface chamada IDescription e INotification.

A interface INotification tem como objetivo definir um contrato para criação de notificações, definindo o mínimo que um classe precisa ter, ela facilita também o uso de injeção de dependência, podendo ajudar na redução de acoplamento entre projetos.

IDescription define um contrato mínimo para uma descrição de uma notificação lançada, assim como sobrescreve o método ToString() para que possa ser usada como um texto simples.

Ainda no projeto de domínio, inclua uma pasta chamada Notifications, e dentro desta pasta, inclua duas classes abstratas, uma chamada Description e outra chamada Notification.

A classe Description é abstrata, e tem como objetivo ser usada como herança para a classe que será a descrição da notificação em si, assim como a classe Notification que será usada como Supertype para a classe de notificação.

Estas quatro classes sustentam todo o core das notificações, fornecendo o mínimo para ser usado em uma entidade de domínio, por exemplo. mas também permite uma extensão do recurso, podendo adicionar outras peculiaridades necessárias.

Erros como notificações

Um dos principais usos de notificações é para tratamento de erros e validações de dados, e para isso, é economizado então uma parada e o lançamento desnecessário de uma exceção do Framework. A proposta aqui é criar um exemplo que usa uma interface e algumas classes básicas: ILevel, Error, ErrorDescription e classes para a severidade do erro.

A classe Error herda da classe abstrata Notification, mas estende a possibilidade de listar erros com descrição e nível, assim como verificar erros somente de um nível de severidade ou simplesmente checar se há erros de um tipo específico ou de modo geral.

No projeto de domínio, na pasta de Interfaces crie uma pasta chamada Errors e dentro dela inclua a interface a seguir:

No projeto de domínio, crie uma pasta chamada Errors e dentro dela inclua as três classes a seguir de nível de severidade:

A classe ErrorDescription recebe as informações básicas de uma notificação e ainda um objeto do tipo ILevel com a severidade do erro para incluir na classe Error.

Com estas classes, personalizamos a notificação para uso com exceções, no qual agora poderá ser usada por outra classe que queira listar e comunicar entre camadas este tipo de informação.

Validando uma entidade

Já temos a estrutura básica para que uma entidade de domínio possa usar este recurso, e ainda ter a possibilidade de verificar se ela é válida ou não para ser usada em outra lógica e/ou salvar no banco de dados. Conseguimos implementar adicionando uma propriedade e dois métodos.

A propriedade Errors é do tipo Error, que é uma instância de notificação, será aqui que as validações serão armazenadas e consultas.

Para permitir que as validações possam ser globais, específicas ou opcionais, criamos um método chamado Validate, que só pode ser disparado na entidade, ou seja, se alguma validação que a maioria está usando não fizer sentido para o objeto pode ser ignorada ou se houver outras validações que são tão específicas para aquela entidade, ela pode ser criada e chamada na entidade.

E para fechar as características mínimas para uma classe poder usar as notificações de erros, temos uma função chamada IsValid, que apenas verifica se há ao menos um erro de nível Critical. Erros dos níveis Warning e Information não tornam a classe inválida neste exemplo.

Porém, para não ficar validando coisas que são comuns ou que a maioria das entidades precisam validar, é possível armazenar estas verificações direto na classe base abstrata do domínio, e para isso criei uma região na classe chamada Validations, onde foi colocada todas as funções que são globais ou bastante usadas. Mesmo assim é preciso chamar na classe principal, pois elas são opcionais, mas estão prontas para usar. Para exemplificar o cenário, escrevi uma função para validar Guid e outra para Nomes, assim como duas descrições de erros, em uma região chamada Errors, com suas devida mensagens e níveis de severidade.

No projeto de domínio, crie uma pasta chamada ValueObjects, e dentro dela inclua as classes a seguir:

Crie outra pasta na raiz do projeto chamada Entities, e dentro dela inclua as classes a seguir:

Comandos, Aplicação e Console

Para testar as notificações, vamos criar os comandos, uma camada de serviço de aplicação e um aplicativo console para simular uma entrada de dados e visualizar os retornos. A montagem desta parte do exemplo não é foco do artigo, se quiser saber os detalhes destes padrões, sugiro que busque informações sobre Commands, Application Layer e Presentation Layer.

Comandos

Na raiz do projeto de domínio, crie uma pasta chamada Commands, e nela inclua uma classe abstrata chamada Command e outra concreta chamada SavePerson, como a seguir:

Com os comandos, a camada de domínio está concluída, agora precisamos criar uma camada de aplicação, que será consumida pela camada de apresentação.

Aplicação

A camada aplicação, conhecida como Service Aplication ou Application Layer, coordena a chamada das camadas de apresentação com o domínio e repositórios. Para criar esta camada, no projeto DomainNotification.Application crie uma pasta chamadas Services, e dentro dela inclua uma classe abstrata chamada Service e outra concreta chamada PersonService, como seguem:

Apresentação

A camada de apresentação poderia ser uma página Web, um App Mobile, um Windows Forms, mas para simplificar o nosso exemplo, vamos usar uma Aplicação Console. Esta aplicação vai receber dois campos que será o Nome e o E-Mail, no qual esperamos que o domínio valide e retorne as notificações. As informações serão transportadas através de DTOs (Data Transfer Objects), que podem o não representar uma entidade de domínio. No nosso caso será a representação da classe Person.

No projeto DomainNotification.Prompt crie uma pasta chamada Dto, e dentro dela inclua uma classe chamada PersonDto, como segue:

E por fim, altere a classe Program para que consuma a camada de aplicação:

A aplicação está concluída, agora podemos testar, como por exemplo, não preencher nenhum campo.

Se preencher o nome corretamente, mas preencher o e-mail de forma incorreta, uma notificação será exibida, sem lançar exceção, informando o problema.

Assim como um notificação de sucesso quando os dados são inseridos corretamente.

Conclusão

Domain Notification ou simplesmente Notification é uma padrão de arquitetura que economiza processamento e torna a aplicação mais clara e versátil, podendo trabalhar com outros padrões e tipos de validação.

Acesse o projeto completo no GitHub:

https://github.com/tiagopariz/DomainNotification

Git: convenção para estrutura de pastas

Desde que comecei trabalhar com repositórios de controle de versão do Git, tenho buscado melhores práticas, tanto para armazenar projetos como versioná-los de forma eficiente. Mas o meu espírito metódico começou perceber que as pessoas e empresas armazenavam coisas muito além dos códigos fontes de seus projetos, criando um verdadeiro ambiente com todas informações e ferramentas usadas centralizadas no mesmo repositório, tornando assim algo que pareça realmente um projeto completo.

Acredito que não há um convenção oficial explicando como a estrutura de pastas deveria ser organizada dentro de um repositório, mas encontrei alguns exemplos, nos quais os desenvolvedores justificam suas escolhas, e estas justificativas fazem muito sentido. Portanto, o melhor modelo, na minha opinião, que encontrei foi este: