Sie sind auf Seite 1von 14

Passo - a – passo para um projeto DDD C# - .NET - MVC5.

Por Gustavo S. Bressan


Baseado no vídeo produzido pelo Eduardo Pires.
http://www.youtube.com/watch?v=i9Il79a2uBU&list=FLqgbgzbiAZAPSu0V3TEQllQ&index=1

1. Iniciar um projeto em branco no VS.


 New Project
 Installed - Other Project Types - Visual Studio Solutions
 Blank Solution
 Colocar o nome da Solução e o diretório onde será criada.

2. Criar Solution Folders para cada camada.


 0 - Presentation
 1 - Services
 2 - Application
 3 - Domain
 4 - Infra
i. 4.1 - Data
ii. 4.2 - CrossCutting

3. Criar um projeto MVC, sem IDENTITY com as pastas MVC, dentro da pasta
Presentation.

4. Apagar o "readme".

5. Criar, dentro da camada de Domain, um projeto do tipo “Class Library”.


 Apague todas as referências do projeto
 Apague a classe criada automaticamente.

6. Criar, dentro da camada de Infra, dentro da pasta DATA, um projeto do tipo “Class
Library”.
 Apague todas as referências do projeto
 Apague a classe criada automaticamente.

7. Criar, dentro do projeto de DOMAIN, três pastas, ENTITIES, INTERFACES e SERVICES.


8. Criar, dentro do projeto de INFRA.DATA, três pastas, CONTEXT, ENTITYCONFIG e
REPOSITORIES.

9. Adicionar referência do projeto DOMINIO no projeto DATA.

10. Criar as Classes para cada entidade do projeto na pasta ENTITIES do projeto DOMAIN.

11. Instalar o EntityFramework neste projeto.

12. Criar uma Classe de contexto, dentro da pasta CONTEXT do projeto INFRA.DATA.
 Fazer a Classe de contexto herdar da Classe DbContext. (System.Data.Entity)
 Adicionar, ao projeto MVC no arquivo Web.Config, a connectionstring para a
conexão com o servidor SQL e o BD.
 Criar um método construtor que recebe ":base("[Nome da String de
Conexão]").
 Criar os DbSet<> para cada entidade do domínio.

13. Habilitar o Migrations para o projeto INFRA.DATA usando o Package Manager


Console.
 Enable-Migrations
 A pasta Migrations será criada automaticamente no projeto.
 Editar o arquivo Configurations.cs e modificar o AutomaticMigrationsEnabled
para "true", para que as modificações feitas nas entidades sejam refletidas
nas tabelas do BD.
 Caso haja necessidade, criar o método SEED para popular as tabelas do banco.
 Executar o Update-Database - verbose -force no Package Manager Console
para que o BD seja criado.

14. Modificar a Classe de contexto, dentro da pasta CONTEXT do projeto INFRA.DATA


 Fazer um override do metodo OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}

 Os dois últimos para evitar “Deletes em cascata” no BD. (IMPORTANTE)


 Para ajudar o EntityFramework a saber que atributos de entidade terminados
em Id serão tratados como Chave Primária.
modelBuilder.Properties().Where(p => p.Name == p.ReflectedType.Name +
"Id").Configure(p => p.IsKey());

 Para que o EntityFramework utilize o tipo VARCHAR para strings ao invés de


usar NVARCHAR.
modelBuilder.Properties<string>().Configure(p => p.HasColumnType("varchar"));

 Para que o EntityFramework utilize o tamanho padrão de 100 caracteres para


os campos string, a não ser que seja especificado na entidade um valor
diferente.
modelBuilder.Properties<string>().Configure(p => p.HasMaxLength(100));

 Sugestão:
i. Caso você utilize alguma outra convenção fazer as mudanças nessa
classe. Ex.:
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries().Where(entry =>
entry.Entity.GetType().GetProperty("DataCadastro") != null))
{
if (entry.State == EntityState.Added)
{
entry.Property("DataCadastro").CurrentValue = DateTime.Now;
}
if (entry.State == EntityState.Modified)
{
entry.Property("DataCadastro").IsModified = false;
}
}
return base.SaveChanges();
}

 Ao criar um novo registro em uma tabela que tenha a propriedade


"DataCadastro" o sistema automaticamente pega DateTime.Now e atribui ao
campo.
 Se um registro já existente estiver sendo MODIFICADO, a propriedade
"DataCadastro" não sofrerá modificação.

15. Criar, na pasta ENTITYCONFIG dentro do projeto INFRA.DATA, uma classe chamada
[Nome da entidade]Configuration, herdando de EntityTypeConfiguration<[Entidade]>,
para CADA ENTIDADE.
 Adicionar configurações para que o EntityFramework saiba como criar as
tabelas no banco da maneira desejada.
 Ex.:
public ProdutoConfiguration()
{
HasKey(p => p.ProdutoID); //Para definir a chave primária.

Property(p => p.Nome).IsRequired().HasMaxLength(250); //Determina que


o campo é NotNull e tem tamanho de 250 caracteres.
Property(p => p.Valor).isRequired(); //Campo NotNull.
HasRequired(p => p.Cliente).WithMany().HasForeignKey(p =>
p.ClienteId); //Para definir o relacionamento com a tabela de cliente, através do
atributo ClientId, com a cardinalidade de 1 - n.
}

Adicionar cada classe de configuração de entidade à classe de Contexto, dentro do método


"OnModelCreating" da seguinte forma:

 modelBuilder.Configurations.Add(new [Nome da Classe de configuração]());

16. Executar o comando Update-Database -verbose -force no Package Manager Console


para que o EntityFramework possa atualizar a base de dados.

Com esses passos o MVC já pode funcionar, mas ainda com muitos acoplamentos. O MVC não
deve saber o que acontece dentro do projeto DATA. O ideal é que o MVC converse com o
contexto através de interfaces.

17. Criar a interface genérica de repositório dentro da pasta INTERFACES no projeto


DOMAIN.
 Definir os métodos genéricos de CRUD (que sejam comuns a TODAS as
entidades).
 Ex.:

public interface IBaseRepository<TEntity> where TEntity : class


{
void Add(TEntity obj);
TEntity GetById(int id);
IEnumerable<TEntity> GetAll();
void Update(TEntity obj);
void Remove(TEntity obj);
void Dispose();
}

18. Criar a Classe de Repositório Base dentro da pasta REPOSITORIES no projeto


INFRA.DATA.
 Implementar a interface IDiposable e a interface de repositório base. Ex.:
 Implementar a lógica de cada método da interface base.
 Ex.:
public class BaseRepository<TEntity> : IDisposable, IBaseRepository<TEntity>
where TEntity : class
{
Contexto Db = new Contexto();
public void Add(TEntity obj)
{
Db.Set<TEntity>().Add(obj);
Db.SaveChanges();
}
public TEntity GetById(int id)
{
return Db.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return Db.Set<TEntity>().ToList();
//Utilizando o NoTracking
//return Db.Set<TEntity>().AsNoTracking.ToList(); - ECONOMIA DE
RECURSOS
}
public void Update(TEntity obj)
{
Db.Entry(obj).State = EntityState.Modified;
Db.SaveChanges();
}
public void Remove(TEntity obj)
{
Db.Set<TEntity>().Remove(obj);
Db.SaveChanges();
}
public void Dispose()
{
}
}

19. Criar a interface especializada de cada entidade, herdando a interface genérica de


repositório.
 Adicionar quaisquer definições de métodos extras, específicos da Entidade,
nesta interface.
 *Ex.:
public interface IProdutoRepository : IBaseRepository<Produto>
{
IEnumerable<Produto> BuscarPorNome(string nome);
}

20. Criar a classe de repositório de cada Entidade, dentro da pasta Repositories dentro do
projeto INFRA.DATA, herdando o repositório base (passando a Entidade como
referência) e implementando a Interface do repositório da Entidade.
 Ex.:
public class ClienteRepository : BaseRepository<Cliente>, IClienteRepository
{
}
public class ProdutoRepository : BaseRepository<Produto>, IProdutoRepository
{
public IEnumerable<Produto> BuscarPorNome(string nome)
{
return Db.Produtos.Where(p => p.Nome == nome);
}
}

21. Se quiser, testar no projeto MVC. Modificar nome da pasta MODELS para ViewModels

22. Criar as ViewModels para cada Entidade (só os atributos, sem comportamentos
(métodos)).

23. Usar DataAnnotations para determinar o comportamento de cada ViewModel


durante o Scaffolding para a View.
 *Ex.:
public class ClienteViewModel
{
[Key]
public int ClienteId { get; set; }

[Required(ErrorMessage = "Preencha o campo Nome")]


[MaxLength(150, ErrorMessage = "Máximos de {0} caracteres")]
[MinLength(2, ErrorMessage = "Minimo de {0} caracteres")]
public string Nome { get; set; }

[Required(ErrorMessage = "Preencha o campo Sobrenome")]


[MaxLength(150, ErrorMessage = "Máximos de {0} caracteres")]
[MinLength(2, ErrorMessage = "Minimo de {0} caracteres")]
public string Sobrenome { get; set; }

[Required(ErrorMessage = "Preencha o campo E-Mail")]


[MaxLength(100, ErrorMessage = "Máximos de {0} caracteres")]
[EmailAddress(ErrorMessage = "Preencha um E-mail válido")]
[DisplayName("E-Mail")]
public string Email { get; set; }

[ScaffoldColumn(false)] //Para que este atributo seja desconsiderado na


criação da view.
public DateTime DataCadastro { get; set; }
}

24. Para mapear a sua ViewModel com a sua entidade de Dominio


 Adicionar referencia do projeto de Dominio na camada MVC.
 Criar uma pasta chamada AutoMapper.
 Criar 3 classes dentro da pasta AutoMapper
i. AutoMapperConfig
ii. DomainToViewModelMappingProfile
iii. ViewModelToDomainMappingProfile
25. Instalar o AutoMapper pelo NuGet, no projeto MVC, pelo Package Manager Console.
 Install-Package AutoMapper (Versão usada para este guia V.3.2.1)

26. Editar a Classe AutoMapperConfig


 Criar o método

public class AutoMapperConfig


{
public static void RegisterMappings()
{
Mapper.Initialize(x =>
{
x.AddProfile<DomainToViewModelMappingProfile>();
x.AddProfile<ViewToDomainMappingProfile>();
});
}
}

27. Editar a Classe DomainToViewModelMappingProfile


 Herdar a classe : Profile
 Criar os métodos:
public override string ProfileName
{
get
{
return "ViewModelToDomainMappings";
}
}

protected override void Configure()


{
Mapper.CreateMap<ClienteViewModel, Cliente>(); //Cria o mapeamento da
ViewModel com a Entidade de Dominio.
Mapper.CreateMap<ProdutoViewModel, Produto>();
}

28. Editar a Classe ViewModelToDomainMappingProfile


 Herdar a classe : Profile
 Criar os métodos:
public override string ProfileName
{
get
{
return "DomainToViewModelMappings";
}

protected override void Configure()


{
Mapper.CreateMap<Cliente, ClienteViewModel>(); //Cria o mapeamento da
Entidade de Dominio com a ViewModel.
Mapper.CreateMap<Produto, ProdutoViewModel>();
}

29. Editar o Global.asax e adicionar a seguinte linha:


 AutoMapperConfig.RegisterMappings();

30. No projeto de DOMINIO, dentro da pasta Interfaces, criar uma nova pasta chamada
Repositories e mover todas interfaces de repositório para a mesma.

31. No projeto de DOMINIO, dentro da pasta Interfaces, criar uma nova pasta chamada
Services

32. Criar a interface IBaseService, contendo as seguintes definições de CRUD.

public interface IBaseService<TEntity> where TEntity : class


{
void Add(TEntity obj);
TEntity GetById(int id);
IEnumerable<TEntity> GetAll();
void Update(TEntity obj);
void Remove(TEntity obj);
void Dispose();
}

33. Criar a interface especializada para cada Entidade.


 Ex.:
public interface IClienteService : IBaseService<Cliente>
{
IEnumerable<Cliente> ObterClientesEspeciais(IEnumerable<Cliente>
clientes);
}
public interface IProdutoService : IBaseService<Produto>
{
IEnumerable<Produto> BuscarPorNome(string nome); //Tem que refletir
dentro da interface os métodos definidos no repositório.
}

34. Criar, dentro do projeto de DOMINIO, dentro da pasta Services, a classe BaseService.
Serviços são utilizados para fazer a ponte entre o domínio e o repositório.
 Ex.:
public class BaseService<TEntity> : IDisposable, IBaseService<TEntity> where
TEntity : class
{
//Fazer a chamado para o repositório
private readonly IBaseRepository<TEntity> _repository;

//Construtor Base
public BaseService(IBaseRepository<TEntity> repository)
{
_repository = repository;
}

public void Add(TEntity obj)


{
_repository.Add(obj);
}
public TEntity GetById(int id)
{
return _repository.GetById(id);
}
public IEnumerable<TEntity> GetAll()
{
return _repository.GetAll();
}
public void Update(TEntity obj)
{
_repository.Update(obj);
}
public void Remove(TEntity obj)
{
_repository.Remove(obj);
}
public void Dispose()
{
_repository.Dispose();
}
}

35. Criar os serviços especialistas, para cada Entidade, na pasta Services do projeto
DOMAIN.
 Ex.:
public class ClienteService : BaseService<Cliente>, IClienteService
{
private readonly IClienteRepository _clienteRepository;

public ClienteService(IClienteRepository clienteRepository)


: base(clienteRepository)
{
_clienteRepository = clienteRepository;
}

public IEnumerable<Cliente> ObterClientesEspeciais(IEnumerable<Cliente>


clientes)
{
return clientes.Where(c => c.ClienteEspecial(c));
}
}

public class ProdutoService : BaseService<Produto>, IProdutoService


{
private readonly IProdutoRepository _produtoRepository;

public ProdutoService(IProdutoRepository produtoRepository)


: base(produtoRepository)
{
_produtoRepository = produtoRepository;
}

public IEnumerable<Produto> BuscarPorNome(string nome)


{
return _produtoRepository.BuscarPorNome(nome);
}
}

36. Criar as Interfaces de aplicação, no projeto APPLICATION (Class Library).


 Criar a pasta Interface
 Criar a interface IAppBaseService com o CRUD básico.
 Ex.:
public interface IAppBaseService<TEntity> where TEntity : class
{
void Add(TEntity obj);
TEntity GetById(int id);
IEnumerable<TEntity> GetAll();
void Update(TEntity obj);
void Remove(TEntity obj);
void Dispose();
}

37. Criar as interfaces especializadas para cada entidade. (Não esquecer de adicionar
referências das entidades de domínio nesse projeto)
 Ex.:
public interface IClienteAppService : IAppBaseService<Cliente>
{
IEnumerable<Cliente> ObterClientesEspeciais(IEnumerable<Cliente> clientes);
}
public interface IProdutoAppService : IAppBaseService<Produto>
{
IEnumerable<Produto> BuscarPorNome(string nome); //Tem que refletir dentro da
interface os métodos definidos no repositório.
}

38. Criar a classes concretas de Application Services.


 Ex.:
public class AppBaseService<TEntity> : IDisposable, IAppBaseService<TEntity>
where TEntity : class
{
private readonly IBaseService<TEntity> _baseService;

public AppBaseService(IBaseService<TEntity> baseService)


{
_baseService = baseService;
}

public void Add(TEntity obj)


{
_baseService.Add(obj);
}
public TEntity GetById(int id)
{
return _baseService.GetById(id);
}
public IEnumerable<TEntity> GetAll()
{
return _baseService.GetAll();
}
public void Update(TEntity obj)
{
_baseService.Update(obj);
}
public void Remove(TEntity obj)
{
_baseService.Remove(obj);
}
public void Dispose()
{
_baseService.Dispose();
}
}
39. Criar as classes especializadas para cada Entidade do Domínio.
 Ex.:
public class ClienteAppService : AppBaseService<Cliente>, IClienteAppService
{
private readonly IClienteService _clienteService;

public ClienteAppService(IClienteService clienteService)


: base(clienteService)
{
_clienteService = clienteService;
}

public IEnumerable<Cliente> ObterClientesEspeciais()


{
return _clienteService.ObterClientesEspeciais(_clienteService.GetAll());
}
}

 Criar os controllers no projeto MVC para cada entidade. O projeto MVC só


precisa ter acesso ao projeto de Application e ao de Domain.
Ex.:
public class ClientesController : Controller
{
private readonly IClienteAppService _clienteApp;

public ClientesController(IClienteAppService clienteApp)


{
_clienteApp = clienteApp;
}

// GET: Clientes
public ActionResult Index()
{
var clienteViewModel = Mapper.Map<IEnumerable<Cliente>,
IEnumerable<ClienteViewModel>>(_clienteApp.GetAll());
return View(clienteViewModel);
}

public ActionResult Especiais()


{
var clienteViewModel = Mapper.Map<IEnumerable<Cliente>,
IEnumerable<ClienteViewModel>>(_clienteApp.ObterClientesEspeciais());
return View(clienteViewModel);
}

// GET: Clientes/Details/5
public ActionResult Details(int id)
{
var cliente = _clienteApp.GetById(id);
var clienteViewModel = Mapper.Map<Cliente, ClienteViewModel>(cliente);

return View(clienteViewModel);
}
 Caso a entidade faça referência a outra entidade faça a injeção de
dependência.
i. Ex.:

private readonly IProdutoAppService _ProdutoApp;

private readonly IClienteAppService _clienteApp;

public ProdutosController(IProdutoAppService produtoApp, IClienteAppService


clienteApp)

_produtoApp = produtoApp;

_clienteApp = clienteApp;

* Criar as ViewBags com a SelectList para os dropdowns das views que precisarem.

40. Instalar o Ninject, no projeto MVC, através do Package Manager Console


 Install-Package Ninject.MVC5

41. Editar o arquivo NinjectWebCommon.cs, localizado na pasta App_Start do projeto


MVC
 No método:
private static void RegisterServices(IKernel kernel//(KERNEL é o container de IoC
do Ninject)
{
}
 Adicionar as referências para as camadas de Aplicação, Serviço e Repositório
 Ex.:
kernel.Bind(typeof(IAppBaseService<>)).To(typeof(AppBaseService<>));
kernel.Bind<IClienteAppService>().To<ClienteAppService>();
kernel.Bind<IProdutoAppService>().To<ProdutoAppService>();

kernel.Bind(typeof(IBaseService<>)).To(typeof(BaseService<>));
kernel.Bind<IClienteService>().To<ClienteService>();
kernel.Bind<IProdutoService>().To<ProdutoService>();

//(Por causa destas referências será necessário adicionar a referência para a ca-
mada de Dados.)
//(O certo seria criar um Modulo em uma camada separada para reduzir
dependências)

kernel.Bind(typeof(IBaseRepository<>)).To(typeof(BaseRepository<>));
kernel.Bind<IClienteRepository>().To<ClienteRepository>();
kernel.Bind<IProdutoRepository>().To<ProdutoRepository>();

42. Criar e ajustar as views para cada ação de cada controller. (Pode usar o scaffolding
para adiantar o processo)
 Trocar o @Html.EditFor... dos campos que forem virar dropdown lists para
@Html.DropDownList recebendo a viewbag e mais um campo em branco.
 Ex.:

@Html.Dropdownlist("ClienteId", String.Empty) //(ClienteId é o nome


da ViewBag).

43. FIM! :D

Das könnte Ihnen auch gefallen