ASP .NET Core - Acesso ao MySQL c/ EF Core usando o Docker no Linux - I

 Neste artigo vamos criar uma aplicação ASP .NET Core MVC usando o Entity Framework Core e acessar o MySql e realizar o CRUD básico usando contêineres do Docker no ambiente Linux.

Este artigo tem o objetivo de mostrar como criar imagens e contêineres Docker para uma aplicação ASP .NET Core MVC e para o banco de dados MySQL e testar a aplicação MVC acessando o MySQL mostrando a comunicação entre os dois contêineres Docker.

Para cumprir nosso objetivo vamos realizar as seguintes tarefas:

  1. Criar uma aplicação ASP .NET Core MVC que acessa o MySQL e faz o CRUD básico usando o EF Core;
  2. Fazer o deploy desta aplicação MVC;
  3. Criar uma imagem da aplicação MVC;
  4. Criar um contêiner usando esta imagem criada;
  5. Criar uma imagem para o banco de dados MySql;
  6. Criar um contêiner para esta imagem do MySql;
  7. Testar a aplicação MVC acessando o MySQL usando os contêineres criados;

Os recursos usados para realizar as tarefas são:

  1. Linux - (Distribuição Ubuntu LTS 18.04 Bionic Beaver)
  2. Docker
  3. .NET Core SDK 2.1
  4. ASP .NET Core 2.1
  5. Entity Framework Core 2.1
  6. Visual Studio Code (Instale as extensões C#, C# Extensions e vscode-icons)

Todos os recursos usados são gratuítos e são multiplataforma, e, a instalação em geral é simples bastando seguir as orientações dadas.

Antes de prosseguir instale as ferramentas indicadas e tenha um bom estudo.

Criando o projeto ASP .NET Core MVC

Abra um terminal de comandos no Linux e crie uma pasta onde o projeto vai ser armazenado usando os comandos mkdir para criar e cd para navegar entre as pastas.

Para o exemplo deste artigo eu crie uma pasta projetos e dentro dela outra pasta produtosmvc onde vou criar o projeto ASP .NET Core MVC.

mkdir projetos
cd projetos
mkdir produtosmvc
cd produtosmvc

Posicionado na pasta onde vai criar o projeto digite o comando para criar o projeto ASP .NET Core MVC usando a ferramenta de linha de comando NET CLI:

dotnet new mvc

Este comando cria um projeto na pasta atual com o mesmo nome da pasta sem autenticação.

Digite o comando a seguir para exibir o conteúdo da pasta : ls -g

Abaixo vemos os arquivos e pastas do projeto criados na pasta atual :

Vamos abrir o código do projeto no Visual Studio Code digitando :  code .

Vemos acima o projeto aberto no VS Code no Linux e o arquivo de projeto produtosmc.csproj mostrando as referências.

Incluindo os pacotes para o MySql

Para poder usar o Entity Framework core no projeto acessando o MySql temos que incluir o pacote com o provedor para o MySql. Vou usar o pacote da Pomelo.

Nota: Veja uma relação de provedores disponíveis neste link

Além disso temos que instalar os seguintes pacotes:

Para instalar um pacote usando a NET CLI usamos o comando : dotnet add package <pacote>

Agora digite os comandos abaixo para incluir os pacotes no projeto:

dotnet add package Pomelo.EntityFrameworkCore.MySql
dotnet add package Pomelo
.EntityFrameworkCore.MySql.Design
dotnet add package
Microsoft.EntityFrameworkCore.Tools

Terminando a execução dos comandos e abrindo o arquivo de projeto .csproj no VS Code devemos ver as referências aos pacotes:

Criando o nosso modelo de dados

Agora que temos o suporte ao EF Core e o provedor para o MySql, vamos criar as classes das entidades para a nossa aplicação.

A nossa aplicação será bem simples e vai gerenciar informações de produtos, asim ela vai ter apenas uma entidade chamada Produto que representa um produto.

Vamos agora criar a classe que representa a nossa entidade na pasta Models do projeto.

Nota: Você pode colocar classes do modelo em qualquer lugar em seu projeto, mas a pasta Models é usada por convenção.

As classes são criadas na pasta Models clicando com o botão direito sobre a pasta, selecionando New C# Classs e a seguir informando o nome da classe.

Vamos iniciar criando o arquivo Produto.cs e nele vamos definir a classe Produto conforme abaixo:

public class Produto
{
        public Produto()
        {}

        public Produto (string nome=null, string categoria=null, decimal preco=0)
        {
            this.Nome = nome;
            this.Categoria = categoria;
            this.Preco = preco;
         }
        public int ProdutoId { get; set; }
        public string Nome { get; set; }
        public string Categoria {get; set; }
        public decimal Preco {get; set; }
}

A propriedade ProdutoId será a coluna de chave primária da tabela de banco de dados que corresponde a essa classe. Por padrão, o Entity Framework interpreta uma propriedade que é chamada de ID ou nome_classeID como sendo a chave primária.(Podemos alterar esse comportamento com annotations)

Nota : O Entity Framework por padrão adota algumas convenções (Conventions) que ele usa para realizar algumas operações.

Criando a classe de contexto do Banco de dados

O Entity Framework permite consultar, inserir, atualizar e excluir dados, usando objetos CLR(Common Language Runtime) conhecidos como entidades; ele mapeia as entidades e relacionamentos que são definidos no seu modelo de entidades para um banco de dados e fornece facilidades para gerenciar as entidades e realizar as operações CRUD.

A principal classe responsável pela interação com os objetos de dados é a classe System.Data.Entity.DbContext (muitas vezes referida como o contexto).

Essa classe de contexto administra os objetos entidades durante o tempo de execução, o que inclui preencher objetos com dados de um banco de dados, controlar alterações, e persistir dados para o banco de dados.

A maneira recomendada para trabalhar com o contexto é definir uma classe que deriva de DbContext e expõe as propriedades de DbSet que representam as coleções das entidades especificadas no contexto.

Essa classe é chamada de classe de contexto do banco de dados e coordena a funcionalidade do Entity Framework para um dado modelo de dados. No código dessa classe você especifica quais entidades estão incluídas no modelo de dados. Você também pode personalizar determinado comportamento do Entity Framework. Neste projeto, a nossa classe de contexto será chamada AppDbContext.

Para simplificar eu vou criar essa classe na pasta Models. Então crie o arquivo AppDbContext.cs na pasta Models e a seguir inclua o código abaixo na classe AppDbContext:

Este código cria uma propriedade DbSet para cada a entidade Produto. Na terminologia Entity Framework, um conjunto de entidades corresponde a uma tabela de banco de dados e uma entidade corresponde a uma linha na tabela.

Criando a classe para alimentar o banco de dados

Precisamos agora definir os dados iniciais que serão incluidos na aplicação quando o banco de dados for criado e estiver vazio.

Para isso vamos criar um arquivo chamado Populadb.cs na pasta Models com o código abaixo:

using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
namespace produtosmvc.Models
{
    public static class Populadb
    {
         public static void IncluiDadosDB(IApplicationBuilder app) 
         {
            IncluiDadosDB(
                app.ApplicationServices.GetRequiredService<AppDbContext>());
         }
        public static void IncluiDadosDB(AppDbContext context)
        {
            System.Console.WriteLine("Aplicando Migrations...");
            context.Database.Migrate();
            if (!context.Produtos.Any()) 
            {
                System.Console.WriteLine("Criando dados...");
                context.Produtos.AddRange(
                    new Produto("Luvas de goleiro", "Futebol", 25),
                    new Produto("Bola de basquete", "Basquete", 48.95m),
                    new Produto("Bola de Futebol", "Futebol", 19.50m),
                    new Produto("Óculos para natação", "Aquáticos", 34.95m),
                    new Produto("Meias Grandes", "Futebol", 50),
                    new Produto("Calção de banho", "Aquáticos", 16),
                    new Produto("Cesta para quadra", "Basquete", 29.95m)
                );
                context.SaveChanges();
            } else {
                System.Console.WriteLine("Dados já existem...");
            }
        }
    }
}

O método estático IncluiDadosDB cria um objeto de contexto do banco de dados e o utiliza para adicionar objetos Produto no banco de dados usando o método AddRange.

A declaração mais importante na classe Populadb é :  context.Database.Migrate()

O EF Core gerencia o esquema do banco de dados usando um recurso chamado Migrations, que geralmente é aplicado ao banco de dados por meio de uma ferramenta de linha de comando. Isso não funciona quando usamos o Docker porque é difícil executar etapas de configuração manual ao implantar um aplicativo.

Em vez disso, o método Database.Migrate() é chamado durante a inicialização do aplicativo para aplicar quaisquer migrações pendentes ao banco de dados.

Isso garante que o esquema do banco de dados será criado sem a necessidade de qualquer intervenção de linha de comando.

Registrando o contexto com injeção de dependência

A ASP.NET Core implementa a injeção de dependência por padrão. Os serviços (como o contexto de banco de dados do EF) são registrados com injeção de dependência durante a inicialização do aplicativo.

Componentes que requerem esses serviços (como controladores MVC) fornecem esses serviços através de parâmetros do construtor. Mais adiante iremos definir no construtor do controlador a instância do contexto.

Para registrar o nosso contexto AppDbContext como um serviço, abra o arquivo Startup.cs e adicione as linhas realçadas ao método ConfigureServices:

using Microsoft.EntityFrameworkCore;
using produtosmvc.Models;
...
....

// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { ... var host = Configuration["DBHOST"] ?? "localhost"; var port = Configuration["DBPORT"] ?? "3306"; var password = Configuration["DBPASSWORD"] ?? "numsey"; services.AddDbContext<AppDbContext>(options => options.UseMySql($"server={host};userid=root;pwd={password};" + $"port={port};database=lojadb"));
            // Add framework services.
            services.AddMvc();
        }
....

O nome da string de conexão é passada para o contexto pela chamada do método no objeto DbContextOptionsBuilder.

A string de conexão especifica um banco de dados identificado pelo nome lojadb.

A senha utilizada aqui (numsey) deverá ser usada quando criarmos o contêiner para o MySql.

No método Configure() vamos chamar o método IncluiDadosDB da classe Populadb:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            Populadb.IncluiDadosDB(app);
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
 }

Na primeira execução a chamada ao método IncluiDadosDB() vai aplicar o script de migração que esta pendente e criar o banco de dados lojadb e a tabela Produtos.

Criando o script de migração

Continuando, vamos criar o script de migração inicial do Entity Framework Core que irá definir o schema para a aplicação com base no arquivo AppDbContext e na classe Produto.

Vamos usar a ferramenta de linha de comando NET CLI e usar o comando :

dotnet ef migrations add ProdutosInicial

Com isso estamos usando os recursos do migrations que vai gerar o script para criar o banco de dados e a tabela da nossa aplicação.

Examinando a estrutura da nossa aplicação no VS Code teremos o seguinte:

Observe que foi criada a pasta Migrations contendo os arquivos usados para fazer a migração.

No arquivo 20181108140213_ProdutoInicial temos o script que vai gerar a tabela Produtos.

Desta forma temos uma migração pendente que será aplicada pelo comando context.Database.Migrate() que definimos no método IncluiDadosDB da classe Populadb.

Na próxima parte do artigo vamos criar o controller e as views para realizar o CRUD básico e gerenciar informações de produtos.

Acompanhe a introdução ao Docker nesta série de artigos sobre o assunto.

Deus nunca foi visto por alguém. O Filho unigênito, que está no seio do Pai, esse o revelou.
João 1:18

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti