ASP .NET Core - Implementando Clean Architecture - III

 Hoje vamos continuar a apresentar os conceitos e princípios que nos ajudam a implementar uma arquitetura aderente aos princípios da Clean Architecture.

Continuando o artigo anterior vamos prosseguir definindo o projeto  CleanArch.Infra.IoC.

Definindo o contêiner de dependências

Vamos criar mais um projeto do tipo Class Library (.NET Core) em nossa solução CleanArch.

Para isso clique com o botão do mouse sobre a solução e selecione Add-> New Project;

Escolha o template Classe Library(.NET Core) a seguir informe o nome CleanArch.Infra.IoC e clique em Create;

No projeto criado vamos remover o arquivo Class1.cs e alterar o <TargetFramework> do arquivo de projeto para net5.0.

Neste projeto vamos incluir a referência ao pacote :  Microsoft.Extensions.DependencyInjection via Nuget.

Após isso precisamos incluir neste projeto as referências aos projetos : Application, Domain e Infra.Data

Para isso clique com o botão direito do mouse sobre o projeto e selecione Add-> Project Reference;

Na janela a seguir marque os projetos conforme mostra a figura:

Agora vamos criar a classe do contêiner de dependências neste projeto será chamada DependencyContainer.cs:

using CleanArch.Application.Interfaces;
using CleanArch.Application.Services;
using CleanArch.Domain.Interfaces;
using CleanArch.Infra.Data.Repositories;
using Microsoft.Extensions.DependencyInjection;
namespace CleanArch.Infra.IoC
{
    public class DependencyContainer
    {
        public static void RegisterServices(IServiceCollection services)
        {
            services.AddScoped<IProductService, ProductService>();
            services.AddScoped<IProductRepository, ProductRepository>();
        }
    }
}

Nesta classe estamos registrando os serviços para o repositório e para o produto e por isso precisamos referenciar os projetos onde definimos as interfaces e implementações do produto e do repositório.

Observe como a classe conecta nossas interfaces e suas implementações de vários projetos em um único ponto de referência. Esse é o propósito da camada IoC : fazer a inversão da dependência.

Além disso, usamos o tempo de vida AddScoped para os serviços o que significa que os objetos usados serão iguais dentro do mesmo request mas diferentes em requisições distintas, ou seja, cada request obtém uma nova instância do serviço.

Agora precisamos fazer com que o projeto UI.MVC tenha conhecimento que este container que criamos existe. Para isso vamos criar o método RegisterServices na classe Startup no projeto CleanArch.UI.MVC logo após o método Configure:

...
        public void RegisterServices(IServiceCollection services)
        {
            DependencyContainer.RegisterServices(services);
        }
...

E aqui teremos que incluir uma referência ao projeto Infra.IoC no projeto UI.MVC para poder usar DependencyContainer.

O toque final é incluir a chamada a RegisterServices() no método ConfigureServices() do projeto UI.MVC:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDatabaseDeveloperPageExceptionFilter();
            services.AddDbContext<ProductDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("ProductConnection")));
            RegisterServices(services);
            services.AddDatabaseDeveloperPageExceptionFilter();
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();
            services.AddControllersWithViews();
        }

E com isso concluímos a implementação dos projetos que representam as camadas da nossa aplicação em nossa solução.

Neste momento a estrutura da nossa solução esta definida da seguinte forma:

A seguir temos as interfaces, implementações. view models e classes definidas em cada camada:

Vamos a seguir tratar com a camada de interface ou seja com o projeto CleanArch.UI.MVC e definir os controllers e as views.

Tratando a interface com o usuário : Definindo controllers e views

No projeto UI.MVC na pasta Controllers vamos criar o controlador ProductsController:   

Clique com o botão direito sobre a pasta Controllers e selecione Add ->  Controller;

A seguir selecione MVC Controller Empty e clique em Add;

Informe o nome ProductsController e clique em Add;

A seguir inclua o código abaixo neste controlador:  

Neste controlador injetamos uma instância do serviço do produto e passamos  a View Model ProductViewModel para a nossa view Index.

Vamos criar a view Index.cshtml na pasta /Views/Products.

Se a pasta Products não for criada na pasta Views teremos que criar a pasta antes.

A seguir clique com o botão direito sobre a pasta Products e selecione Add->View;

Selecione Razor View Empty e clique em Add;

Informe o nome Index.cshml e clique em Add;

A seguir inclua o código abaixo no arquivo Index.cshtml:

@model CleanArch.Application.ViewModels.ProductViewModel
<table id="book" class="table table-bordered table-hover">
    <thead>
        <tr class="">
            <th>Name</th>
            <th>Description</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model.Products)
        {
            <tr style="height: 60px;">
                <td>@product.Name</td>
                <td>@product.Description</td>
                <td>@product.Price.ToString("c")</td>
            </tr>
        }
    </tbody>
</table>

Depois disso, vamos ajustar o código no arquivo _Layout.cshtml na pasta Views/Shared e adicionar um link de navegação para a  View que acabamos de criar.

Observe que ele aponta para o controlador Products e a para a Action Index:

...
 <ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
          <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
   </li>
   <li class="nav-item">
          <a class="nav-link text-dark" asp-area="" asp-controller="Products" asp-action="Index">Products</a>
  </li>
</ul>
...

Nota: Vou alterar também a view Index.cshtml da pasta Views/Home.

Agora é só alegria...

Executando o projeto teremos:

Podemos executar o projeto usando o comando dotnet watch run a partir da pasta onde esta o projeto MVC:

Como exemplo vou entrar na pasta do projeto :

E a seguir vou entrar na pasta do projeto CleanArch.UI.MVC e vou executar o comando: dotnet watch run

O resultado será exibido conforme figura  abaixo:

E o projeto será aberto no navegador padrão. Com isso podemos fazer alterações no código sem ter que interromper a execução do projeto

Para testar o login e o Register basta incluir o atributo [Authorize] no método Action Index do controlador ProductsController para restringir o acesso.

         [Authorize]
        public IActionResult Index()
        {
            ProductViewModel model = _productService.GetProdutcs();
            return View(model);
        }

Agora basta executar e agora teremos que registrar um usuário e fazer o login para acessar os produtos:

Pegue o código do projeto aqui:  CleanArch.zip

"Mas Deus prova o seu amor para conosco, em que Cristo morreu por nós, sendo nós ainda pecadores."
Romanos 5:8

Referências:


José Carlos Macoratti