Tutorial ASP.NET MVC 5 + DDD + EF + AutoMapper + IoC + Dicas e Truques

Arquitetura de Sistemas Corporativos é um tema muito menos explorado do que ASP.NET MVC 5 e nem por isso é menos importante (na verdade é bem mais), neste vídeo tutorial eu mostrarei como criar uma arquitetura padrão DDD utilizando ASP.NET MVC 5.2, Entity Framework, AutoMapper, IoC com Ninject e muitas dicas para criar uma arquitetura modelo e totalmente responsável.

ASP.NET MVC 5 + DDD + EF + AutoMapper + IoC

Como poderão acompanhar nos slides e no vídeo ASP.NET MVC é apenas a ponta do iceberg em uma aplicação corporativa. Quando entramos no mundo real os exemplos dos artigos de sites e livros não nos atendem mais e é necessário buscar mais conhecimento para criar uma aplicação robusta, responsável, testável, escalável e de fácil manutenção.

O modelo DDD (Domain Driven Design) atende muito bem cenários de aplicações corporativas e eu utilizo muito em meus projetos profissionais e pessoais.

Neste vídeo tutorial você aprenderá

  • Criar uma solução padrão DDD
  • Separar a aplicação em camadas
  • Entidades de Domínio
  • Classes de Serviço
  • Criar Contratos (Interfaces)
  • Repositório Genérico
  • Repositório Especializado
  • Criar um Contexto do Entity Framework
  • Trabalhar com Migrations
  • Criar novas convenções do Entity Framework
  • Remover algumas convenções do Entity Framework
  • Sobrescrever o método SaveChanges para persistência de dados
  • Programar com CodeFirst
  • Utilizar FluentAPI para modelar tabelas
  • Criar Relacionamentos entre Entidades e refletindo nas tabelas do banco de dados.
  • Criar e utilizar a camada de Application
  • Trabalhar com classes genéricas de Entidades
  • Abstrair camadas com Injeção de Dependência (IoC)
  • Implementar o Ninject como container de IoC (DI)
  • Utilizar ViewModels
  • Utilizar DataAnnotations para validação de formulários
  • Mapear ViewModels x Entidade de Domínio com AutoMapper
  • Muitas dicas para acelerar sua produção

Este conteúdo é aplicado no meu curso de ASP.NET MVC 5 – Enterprise Applications com uma carga horária de 16 horas, com todo o embasamento teórico, técnico e prático, muitos outros patterns, testes, mocks, serviços REST, manipulação de filtros do ASP.NET MVC e etc são abordados no curso para uma preparação completa do futuro arquiteto desenvolvedor.

SLIDES

VÍDEO (3h00 de duração)

* Assine meu canal no Youtube 🙂

SOURCE

Para download do projeto clique aqui (logo será transferido para o GitHub)

Referências

Vamos continuar enriquecendo o assunto, poste aqui sua opinião ou dúvida 😉

ASP.Net MVC – AutoMapper e View Models

O AutoMapper é uma biblioteca pequena e simples construída para resolver um problema aparentemente complexo, que é livrar-se de um código que mapeou um objeto para outro. Este tipo de problema é muito comum e relativamente trabalhoso de resolver,  a ferramenta AutoMapper atua nesse cenário de forma simples e elegante.

ASP.Net MVC AutoMapper

No artigo anterior foi abordado o padrão View Model no ASP.Net MVC, esse padrão ajuda a organizar o código, pois divide as responsabilidades entre as Models de domínio e as Models que atendem Views, evitando que as Models de domínio sejam alteradas e poluídas com dados desnecessários ao domínio.

A primeira técnica de trabalhar com View Models foi abordada no artigo anterior.
A técnica abordada neste artigo é mais complexa e necessita de um mapeamento entre objetos que é feito com a ajuda da ferramenta AutoMapper.

No livro Padrões de Arquitetura de Aplicações Corporativas, Martin Fowler descreve um padrão base chamado Mapper. O AutoMapper foi desenvolvido por Jimmy Bogard, um dos autores do livro ASP.Net MVC 4 in Action.

Mapeando uma Model de domínio para uma View Model

O cenário deste exemplo é baseado em um sistema muito simples que consulta os dados de um cliente cadastrado e informa um número da sorte gerado randomicamente para este cliente.

Neste cenário possuímos a Model de domínio (cliente).

using System;

namespace MvcMapping.Models
{
    public class Cliente
    {
        public string Nome { get; set; }
        public string Sobrenome { get; set; }
        public DateTime DataNascimento { get; set; }
        public bool Ativo { get; set; }
    }
}

Note que não existe referência ao dado de número da sorte, pois ele é exibido apenas na View e não é armazenado com os dados de cliente, logo torna-se desnecessário fazer parte da modelagem da Model.

Na técnica apresentada anteriormente a solução seria criar uma View Model com uma propriedade do tipo cliente e complementar com dados adicionais a serem exibidos na View.
Este artigo irá abordar outra técnica que consiste em criar uma classe com a mesma estrutura de cliente e mais os novos dados adicionais, chamaremos ela de ClienteViewModel e estará disponível em uma pasta raiz do projeto MVC chamada ViewModels.

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMapping.ViewModels
{
    public class ClienteViewModel
    {

        [Required(ErrorMessage = "Preencher campo Nome")]
        public string Nome { get; set; }

        public string Sobrenome { get; set; }

        [Required(ErrorMessage = "Preencher campo Data de Nascimento")]
        [Display(Name = "Data de Nascimento")]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
        [DataType(DataType.Date, ErrorMessage="Data em formato inválido")]
        public DateTime DataNascimento { get; set; }

        public bool Ativo { get; set; }

        public int NumeroDaSorte { get; set; }
    }
}

Na classe ClienteViewModel possuímos a mesma estrutura de clientes, mais o dado adicional de número da sorte e os DataAnnotations para validação de formulário.

Até este momento já é possível listar três benefícios imediatos:

  • A Model de domínio não precisou ser modificada sem necessidade.
  • A Model de domínio não está poluída com DataAnnotations de validação de formulário.
  • A manutenção destas classes torna-se muito mais fácil, uma vez que a Model de domínio não está amarrada às características de uma View.

Após a separação das responsabilidades temos uma Model e uma View Model, ambas representando a entidade cliente, agora é necessário mapear um objeto ao outro para que a ClienteController receba a Model cliente e responda para View uma ClienteViewModel (e vice-versa), esse trabalho é executado pelo AutoMapper.

Configurando o AutoMapper no projeto ASP.Net MVC

Primeiramente é necessário configurar as referências das bibliotecas do AutoMapper e isto pode ser feito facilmente com o NuGet

PM> Install-Package AutoMapper

No projeto MVC crie uma pasta vazia chamada Mappers, dentro desta pasta será necessário criar uma classe que servirá de configuração dos profiles de mapeamento (Model > View Model) e (View Model > Model), esses profiles de mapeamento foram separados em dois arquivos, confira como abaixo como criar cada um deles.

Classe AutoMapperConfig

using AutoMapper;

namespace MvcMapping.Mappers
{
    public class AutoMapperConfig
    {
        public static void RegisterMappings()
        {
            Mapper.Initialize(x =>
            {
                x.AddProfile<DomainToViewModelMappingProfile>();
                x.AddProfile<ViewModelToDomainMappingProfile>();
            });
        }
    }
}

Classe DomainToViewModelMappingProfile

[UPDATE – 12/2015]Não é mais possível fazer o override do ProfileName nas novas versões do AutoMapper. Basta não sobrescrever esta property

using AutoMapper;
using MvcMapping.Models;
using MvcMapping.ViewModels;

namespace MvcMapping.Mappers
{
    public class DomainToViewModelMappingProfile : Profile
    {
        // Não realizar este override na versão 4.x e superiores
        public override string ProfileName
        {
            get { return "DomainToViewModelMappings"; }
        }

        protected override void Configure()
        {
            Mapper.CreateMap<Cliente, ClienteViewModel>();
        }
    }
}

Classe ViewModelToDomainMappingProfile

using AutoMapper;
using MvcMapping.Models;
using MvcMapping.ViewModels;

namespace MvcMapping.Mappers
{
    public class ViewModelToDomainMappingProfile : Profile
    {
        // Não realizar este override na versão 4.x e superiores
        public override string ProfileName
        {
            get { return "ViewModelToDomainMappings"; }
        }

        protected override void Configure()
        {
            Mapper.CreateMap<ClienteViewModel, Cliente>();
        }
    }
}

Esta é a estrutura necessária para configurar o AutoMapper de forma a utilizar o mínimo possível de código de mapeamento em outras classes da aplicação.

  • AutoMapperConfig > Inicializa os profiles de mapeamento (Model > View Model) e (ViewModel > Model).
  • DomainToViewModelMappingProfile > Profile de mapeamento (Model > View Model)
  • ViewModelToDomainMappingProfile > Profile de mapeamento (View Model > Model)

Confira como o projeto ficou estruturado

Projeto ASP.Net MVC AutoMapper

Neste momento resta apenas configurar que a classe AutoMapperConfig seja inicializada junto com a aplicação para registrar os profiles de mapeamento, essa configuração é feita no arquivo Global.asax

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using MvcMapping.Mappers;

namespace MvcMapping
{

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

            // Configurando o AutoMapper para registrar os profiles
            // de mapeamento durante a inicialização da aplicação.
            AutoMapperConfig.RegisterMappings();
        }
    }
}

O AutoMapper está devidamente configurado na aplicação, no próximo passo será feita a conversão da Model cliente para a ClienteViewModel na Controller através do mapeamento que foi criado, confira como ficou o código da ClienteController

using System;
using System.Web.Mvc;
using MvcMapping.Models;
using MvcMapping.ViewModels;
using AutoMapper;

namespace MvcMapping.Controllers
{
    public class ClienteController : Controller
    {
        public ActionResult Index()
        {
            var rdnGen = new Random();

            // Um fake de uma consulta de cliente na base de dados.
            var cliente = new Cliente {
                                            Nome = "Eduardo",
                                            Sobrenome = "Pires",
                                            DataNascimento = Convert.ToDateTime("24/04/1982"),
                                            Ativo = true,
                                      };

            // Transformando a Model Cliente em ClienteViewModel
            var clienteView = Mapper.Map<Cliente, ClienteViewModel>(cliente);

            // Atribuindo valor aos dados adicionais da entidade Cliente
            clienteView.NumeroDaSorte = rdnGen.Next(1, 100);

            return View(clienteView);
        }
    }
}

Note que foi necessário apenas uma linha para transformar a Model Cliente em ClienteViewModel. De forma muito elegante foi criado um objeto do tipo ClienteViewModel já populado com os dados existentes no objeto Cliente.

A partir deste momento o AutoMapper está fazendo o trabalho de mapeamento e a View está recebendo uma View Model compatível com suas necessidades, confira o código da View

@model MvcMapping.ViewModels.ClienteViewModel

@{
    ViewBag.Title = "Sorte do Dia";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>

<table>
    <tr>
        <td>
            @Html.LabelFor(m => m.Nome)
            @Html.DisplayFor(m => m.Nome)
        </td>
    </tr>
    <tr>
        <td>
            @Html.LabelFor(m => m.Sobrenome)
            @Html.DisplayFor(m => m.Sobrenome)
        </td>
    </tr>
    <tr>
        <td>
            @Html.LabelFor(m => m.DataNascimento)
            @Html.DisplayFor(m => m.DataNascimento)
        </td>
    </tr>
    <tr>
        <td>
            @Html.LabelFor(m => m.Ativo)
            @Html.DisplayFor(m => m.Ativo)
        </td>
    </tr>
    <tr>
        <td>
            @Html.LabelFor(m => m.NumeroDaSorte)
            @Html.DisplayFor(m => m.NumeroDaSorte)
        </td>
    </tr>
</table>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Para mapear mais Models / View Models basta editar os arquivos DomainToViewModelMappingProfile e ViewModelToDomainMappingProfile com os mapeamentos necessários.

Achou muito trabalhoso ter que montar a estrutura de pasta e os 3 arquivos de mapeamento? Existe uma forma que dispensa toda essa configuração (inclusive inicialização no Global.asax), basta adicionar uma linha a mais em cada momento que houver o mapeamento, confira.

public class ClienteController : Controller
{
    public ActionResult Index()
    {
        var rdnGen = new Random();

        // Um fake de uma consulta de cliente na base de dados.
        var cliente = new Cliente {
                                        Nome = "Eduardo",
                                        Sobrenome = "Pires",
                                        DataNascimento = Convert.ToDateTime("24/04/1982"),
                                        Ativo = true,
                                    };

        // Criando o Mapeamento por demanda.
        Mapper.CreateMap<Cliente, ClienteViewModel>();

        // Transformando a Model Cliente em ClienteViewModel
        var clienteView = Mapper.Map<Cliente, ClienteViewModel>(cliente);

        // Atribuindo valor aos dados adicionais da entidade Cliente
        clienteView.NumeroDaSorte = rdnGen.Next(1, 100);

        return View(clienteView);
    }
}

Apesar de ser mais simples eu pessoalmente não recomendo utilizar o mapeamento desta forma, pois além de somar uma linha a mais em todo momento de executar o mapeamento, o comando de criação de mapeamento não fica centralizado, é difícil ter visão dos mapeamentos já existentes e dificulta também a manutenção.

Resumo

Utilizar o AutoMapper é muito simples conforme foi exemplificado, colabora para adoção do padrão View Model e evita a necessidade de escrever extensos códigos de mapeamento, assim proporcionando mais agilidade no desenvolvimento e facilitando a manutenção, e claro, o código final fica com um aspecto muito mais elegante.

Existem outras ferramentas para mapeamento com a mesma finalidade, a mais popular até o momento é o AutoMapper.

Referências

Nota

“Como mencionado no artigo anterior o padrão View Model está presente no MVC, MVP e MVVM, este artigo aborda a utilização deste padrão para MVC.”

Espero que este artigo ajude a entender o conceito do padrão View Model e o mapeamento de objetos através do AutoMapper.

Feedbacks são sempre muito bem vindos, utilize os comentários abaixo.