Atenção: esse artigo tem uma palestra complementar. Clique e assista!

Do que trata o artigo

Veremos neste artigo como criar uma aplicação de transferência de arquivos através de um site feito em ASP.NET. Para a construção deste aplicativo iremos utilizar ASP.NET Web Forms, alguns conceitos do DDD (Domain-Driven Design) e NHibernate.


Para que serve

Atualmente quando uma empresa quer dar acesso aos seus arquivos para funcionários externos, recorre aos recursos de FTP, que geralmente são difíceis de usar ou não apresentam uma segurança satisfatória. Veja neste artigo como criar uma aplicação ASP.NET com esse objetivo, utilizando NHibernate e algumas boas práticas do DDD.

Em que situação o tema é útil

Esse artigo pode ser útil como referência para qualquer aplicação ASP.NET onde seja necessário realizar upload ou download de arquivos do servidor. Ele também pode ajudar quem estiver procurando por exemplos práticos de utilização do DDD e NHibernate em aplicações ASP.NET Web Forms.

Resumo do DevMan

Uma pequena empresa de desenvolvimento de software precisa disponibilizar uma série de arquivos para seus funcionários externos e eventualmente até para alguns de seus clientes. Além disso alguns desses usuários vão precisar subir arquivos para o mesmo servidor.

Para atender essa necessidade resolvemos criar uma aplicação ASP.NET Web Forms, ao invés do uso de um simples serviço de FTP. O motivo principal é que os usuários precisam de uma interface Web simples, de fácil utilização e com o mínimo controle de segurança por usuário.

Além disso, a empresa espera que essa aplicação evolua, agregando novas funcionalidades, integrando-se com outros sistemas e adotando novas tecnologias que estão para surgir e se consolidar em 2010. Esse é o cenário da aplicação que vamos desenvolver ao longo deste artigo.

O requisito principal é simples: precisamos liberar o acesso a alguns arquivos do servidor para quem está fora do escritório. Além disso, alguns usuários com nível de permissão mais elevado poderão criar subpastas, subir arquivos e até excluir arquivos ou pastas. Nós sabemos que essa é uma aplicação trivial, e que existem dezenas de soluções prontas no mercado que atendem desde essa simples questão até cenários bem mais complexos.

Veja por exemplo o SharePoint da Microsoft. Ele é um portal de colaboração de arquivos, que nos permite um gerenciamendo dos documentos da empresa de uma forma muito mais organizada, também atendendo a necessidade ali de cima. Na outra ponta temos os simples serviços de FTP, que nos permitem expor diretórios do servidor para serem acessados de fora, mediante uma senha de rede.

A nossa situação é a seguinte: nós queremos uma solução mais amigável do que um simples serviço de FTP, que seja mais fácil de usar e permita uma segurança diferenciada. Mas também não queremos algo tão sofisticado como o SharePoint. Além disso, nós queremos uma aplicação que possa evoluir com o tempo. Algo que futuramente possa ser integrado a outros sistemas da empresa, que no futuro nos permita criar mecanismos mais elaborados de log, versionamento, lock de arquivos etc. Uma aplicação que possa ser modificada de acordo com as necessidades e fique com a cara da empresa.

Requisitos funcionais: Domínio

A primeira versão dessa aplicação deverá simplesmente permitir o download, upload, criação de subpastas e exclusão de itens para usuários logados e com as devidas permissões. Teremos uma pasta raiz no servidor, reservada apenas para as subpastas e arquivos que irão trafegar por essa aplicação. Convencionalmente, nenhuma pessoa poderá alterar a estrutura de subpastas e arquivos deste local, isso deve obrigatoriamente ser feito pela aplicação.

O administrador de rede deve se encarregar de blindar o acesso dessa pasta pela rede. Ele também precisará informar com qual usuário a aplicação ASP.NET é executada (geralmente esse é o usuáro do IIS - Internet Information Services), dar as devidas permissões para que ele possa incluir, alterar e excluir pastas e arquivos dentro desta pasta raiz. Dentro da nossa aplicação devemos ter uma referência para essa pasta raiz, que nessa primeira versão pode ser uma informação global fixa (hard-coded) mesmo.

O direito de criação de subpastas na aplicação será dado ao nível do usuário. Já para conseguir ver as subpastas e realizar downloadas dos itens contidos nela o usuário precisa ter direito na respectiva pasta. Dentro da pasta o usuário ainda poderá ter o direito de realizar uploads e até de excluir itens contidos nela.

Outros detalhes certamente irão surgir durante o desenvolvimento e uma revisão do domínio sempre é necessária. Essa é inclusive uma das premissas do DDD. Vamos agora aos requisitos não funcionais.

Requisitos não-funcionais: Arquitetura

Como dito na introdução, um dos motivos de criarmos essa aplicação é porque queremos ter a liberdade de modificá-la como bem entendermos, de acordo com nossas necessidades futuras. Sendo assim esse é o principal requisito não funcional: devemos criar essa aplicação de forma que ela nos permita uma fácil manutenção futura.

Apesar de a aplicação tratar de transferência de arquivos que estão em uma pasta do sistema de arquivos de um servidor Windows, vamos precisar de um banco de dados para armazenar usuários, nomes das pastas e permissões de cada usuário em cada pasta. O consenso geral decidiu pelo SQL Server 2008, que já é um banco que todos da equipe conhecem.

Nossa equipe de desenvolvedores está envolvida em diversos projetos, a maioria deles são projetos antigos, que surgiram da modelagem de estrutura de bancos de dados, e usam ADO.NET e DataSets como camada de persistência.

Porém, estamos aos poucos adotando boas práticas de orientação a objetos, design patterns, e é claro o DDD (Domain-Driven Design). Sabemos que o DDD é uma cultura a ser adotada aos poucos, e por isso vamos aplicar alguns de seus conceitos na modelagem dessa aplicação, para que as ideias do DDD passem, aos poucos, a serem cultivadas pela equipe.

Note que o DDD aqui nesse projeto é mais como um guia de boas práticas, servindo principalmente para avaliarmos e conhecermos essas técnicas, e não podemos comprometer a entrega da aplicação por conta disso. Em alguns pontos certamente teremos que abrir mão de algumas regras para ter uma aplicação funcionando no tempo previsto.

Com o DDD surge a necessidade de definirmos uma ferramenta ORM, já que não temos a intenção de escrever todo o mecanismo de persistência com o banco de dados. E também porque um dos princípios fundamentais do DDD é que o domínio da aplicação não tem a menor ciência de como os dados serão armazenados.

A escolha aqui é entre NHibernate e ADO.NET Entity Framework. O NHibernate se encaixa perfeitamente em uma estrutura modelada com o DDD, pois permite a modelagem de entidades através da técnica POCO (Plain Old CLR Objects), o que possibilita termos um modelo totalmente desacoplado do mecanismo de persistência. Já a atual versão do Entity Framework não permite isso.

A nova versão do EF, que está pra surgir em Abril / 2010, promete resolver essa questão, mas não vamos arriscar com isso agora. Se futuramente resolvermos trocar o NHibernate pelo ADO.NET Entity Framework, iremos fazer apenas se o nosso domínio permanecer intacto. Essa premissa do DDD é uma das que a equipe mais se identificou, pois garante que o coração da aplicação fique totalmente isolado de banco de dados, mecanismos de persistência e da camada de apresentação.

Essa sim foi a decisão mais difícil a ser tomada: qual tecnologia Web vamos usar para a camada de apresentação. Tivemos várias discussões técnicas, onde houve muita excitação quanto ao uso de tecnologias relativamente novas como ASP.NET MVC, Silverlight e até o AJAX 4 (ainda em Beta até o fechamento deste artigo) . Porém, no consenso geral, concordamos que nossa equipe atual precisaria ser capacitada em uma dessas tecnologias, o que acarretaria num atraso do projeto, e consequentemente num custo maior para desenvolvermos essa primeira versão.

E já que nossa equipe é altamente capacitada em ASP.NET Web Forms, concordamos que essa será a tencologia utilizada nessa primeira versão. Porém, concordamos que a aplicação deve ser desenvolvida de forma que permita uma futura substituição o menos traumática possível do ASP.NET Web Forms, se for o caso.

As decisões tomadas anteriormente já vão garantir parte dessa transição, já que teremos um domínio e uma camada de persistência totalmente isolados da camada de apresentação e que podem facilmente ser reaproveitados em outras tecnologias.

Porém levantou-se uma questão importante: Vamos utilizar algum padrão de desenvolvimento na camada de apresentação? Não faz sentido tentar aplicar MVC (Model-View-Controller) em uma aplicação ASP.NET Web Forms, já que esse padrão já é implícito em aplicações ASP.NET MVC.

Já em aplicações Silverlight/WPF podemos utilizar o mais recente MVVM (Model-View-ViewModel), que é uma excelente escolha. Porém, no ASP.NET Web Forms o MVVM não é aplicável, já que ele depende de avançadas funcionalidades de Binding que hoje só temos no WPF/Silverlight (e futuramente no AJAX 4).

Sendo assim, o padrão que mais se encaixa em aplicações ASP.NET Web Forms hoje é o padrão MVP (Model-View-Presenter), que trabalha com interfaces na camada View, e uma camada Presenteer que se comunica com a View por essas interfaces. Porém a discussão foi: que benefícios vamos ter com esse padrão, já que no futuro ao trocarmos para ASP.NET MVC ou Silverlight, vamos ter que trocar de padrão também?

O único benefício que conseguimos enxergar foi o da testabilidade. O MVP, assim como qualquer outro padrão citado acima, permite a criação de testes unitários na camada de apresentação da aplicação, coisa que não conseguimos fazer apenas com o code-behind do ASP.NET Web Forms.

A questão de testes também foi polêmica. Apesar de todos concordarem que testes unitários são requisitos indispensáveis hoje em dia, decidimos por não criar testes nessa primeira versão da aplicação. O motivo é que precisamos colocá-la em produção o mais rápido possível, e os primeiros usuários dessa aplicação são os próprios desenvolvedores, o que nos permite uma tolerância maior a falhas.

Entretanto, nos comprometemos em criar a aplicação o mais testável possível, principalmente com a adoção dos conceitos do DDD e o desacoplamento das camadas. A única parte que vai ficar de fora vai ser mesmo a camada de apresentação. Optamos, portanto, por não utilizar o padrão MVP, e nossas páginas ASP.NET vão acessar as camadas de persistência e domínio diretamente através do code-behind.

Sabemos que esse não é o melhor dos mundos, e que os mais fanáticos podem dizer que isso fere os princípios do DDD. Mas o que importa é que sabemos dos riscos e benefícios de cada escolha tomada, e estamos empenhados em aprimorar continuamente essa aplicação.

Resumindo todas as decisões tomadas, temos a seguinte arquitetura: criaremos uma aplicação seguindo os conceitos de modelagem do DDD, construindo uma camada de domínio totalmente isolada e que não terá dependência com nada, a não ser o próprio .NET Framework. Teremos uma camada de persistência feita com NHibernate, com funcionalidades de criação da estrutura do banco de dados com base no mapeamento objeto/relacional definido. Usaremos o SQL Server 2008 como banco de dados, porém sabemos que com o NHibernate temos a possibilidade de trocar de banco de dados caso seja necessário. Nossa camada de apresentação será feita em ASP.NET Web Forms sem a adoção de nenhum padrão específico, onde iremos acessar as camadas de domínio e persistência através do code-behind das páginas.

Caso seja necessário no futuro, poderemos criar testes unitários para as camadas de domínio e persistência, sem nenhuma interferência direta nessas camadas. Sabemos que o ponto mais frágil dessa arquitetura está na camada de apresentação, e portanto estamos preparados para substituí-la no futuro, caso haja essa real necessidade.

Criando a estrutura de projetos

Sabendo exatamente o que temos que fazer e como vamos fazer, devemos começar criando uma estrutura de projetos, que serão as camadas da nossa aplicação. Sendo assim, abra o seu Visual Studio 2008 e vá em File / New Project. Como nos mostra a Figura 1, selecione o template Blank Solution, que está disponível em Other Project Types / Visual Studio Solutions. Em Name informe ArqTransfer e clique em OK.

Figura 1. Criando a Solution para a aplicação ArqTransfer

Nesta Solution temos que criar três projetos. O primeiro, do tipo Class Library, que irá se chamar ArqTransfer.Dominio. O segundo projeto será a camada de persistência, também será do tipo Class Library, e se chamará ArqTransfer.Repositorio, para seguirmos a nomenclatura sugerida pelo DDD. O terceiro e último será um projeto do tipo ASP.NET Web Forms, que iremos chamar de ArqTransfer.WebForms. Veja na Figura 2 como estes projetos ficam na janela Solution Explorer

Figura 2. Definindo camadas em projetos separados

Note que as classes default dos projetos ClassLibrary (Class1.cs) foram apagadas, assim como a página Default.aspx, que não será utilizada. Também definimos o projeto ASP.NET como sendo o projeto de StartUp da Solution. A seguir vamos começar com a modelagem do domínio da nossa aplicação.

Domínio

No DDD começamos a modelar nossa aplicação pelo domínio. Não vamos entrar nos detalhes teóricos da modelagem de domínio. Para nós basta saber que precisamos definir um modelo de objetos que represente toda a estrutura de dados e comportamento que a aplicação deverá ter. Usando as terminologias do DDD, temos que modelar:

- Entidades de negócio, que possuem identidade e devem ser persistidas no repositório; Objetos de Valor que na prática funcionam como “objetos auxiliares” do modelo, que não possuem identidade e raramente precisam ser persistidos no repositório. Geralmente são valores imutáveis do domínio, ou também podem ser encarados como projeções específicas de consultas feitas das entidades. Veremos isso na prática logo a seguir.

- O comportamento da nossa aplicação, ou a lógica de negócio, também deve ser definida no domínio, em classes que podemos chamar de Serviços. Como veremos, nem todo o comportamento é simples de ser abstraído no domínio, principalmente pequenas regras que estão intimamente ligadas à interface. Esses são alguns detalhes que vão acabar fugindo das regras do DDD, por conta inclusive das escolhas que fizemos. Veremos claramente onde e quando isso vai acontecer.

- Para que o nosso domínio seja completo, precisamos de alguma forma de comunicação com a camada de Repositório, para que os dados sejam persistidos. Para que isso seja possível, nós definimos na camada de Domínio as Interfaces do Repositório, que deverão ser implementadas na camada de persistência (chamada de Repositório).

...
Quer ler esse conteúdo completo? Tenha acesso completo