Desenvolvendo um projeto ASP.NET MVC de uma aplicação modelo baseada no projeto #workshop-asp-net-core-mvc do professor @acenelio a partir do curso "C# COMPLETO Programação Orientada a Objetos + PROJETOS" na Udemy. O meu propósito com este projeto é atualizar a versão desenvolvida em .NET 2.1 para a versão mais recente do framework (.NET 8.0)
Pretendo com este README explicitar o que é necessário para o desenvolvimento da aplicação em uma verão mais recendo do .NET, não necessariamente me propondo a explicar toda a aplicação. Por esta razão, é necessário ter uma mínima noção de MVC + ASP.NET ou que esteja fazendo o curso do @acenelio.
Existem diferentes ferramentas de desenvolvimento para utilizar o C#/.NET, sejam IDEs (como o Visual Studio 2022 Community da Microsoft ou Rider da JetBrains) ou editores de texto (o melhor exemplo é o Visual Studio Code com extensões razoáveis para desenvolver em .NET — C# e C# Dev Kit). No caso, utilizarei os exemplos com o VS 2022 e o VS Code, já que o no caso do VS Code é necessário rodar todas as instruções no .NET CLI.
Antes de mais nada, volto a reforçar que, para o projeto eu utilizei a versão 8.0.5 (SDK 8.0.300) do .NET 8, então, verifique sua versão com o comando:
dotnet --versionou veja se há algum SDK desta versão em sua máquina e utilize-a:
dotnet --list-sdks
Para começar a aplicação, vamos inicializar um projeto com ASP.NET MVC.
Com .NET CLI:
dotnet new mvc -o YourMvcProject
Ou com o template padrão MVC do Visual Studio (na interface, acesse File>New>Project ou Ctrl+Shift+N):
Como a implementação do projeto no curso já é um tanto quanto antiga, pois a versão do .NET 2.1 é de 2018, sendo que o patch mais recente é de 2021. Aliás, no próprio site de download da versão não recomenda o uso da versão porque esta não recebe mais suporte, ou seja, é insegura - recomendando o .NET 8.0 (que é LTS).
IMPORTANTE: novamente, não irei me ater em explicar sobre o MySQL, MVC ou Entity Framework, é necessário já ter noções básicas para reproduzir o projeto de modo fluído.
Agora, para podermos manipular o código sem problema, vamos instalar o pacote do MySQL (considerando que você já tenha instaldo SGBD em sua máquina) para nossa aplicação pelo Nuget, o MySql.Data 8.4.0
(que foi o pacote que eu utilizei - fique a vontade para mudanças ou sugestões) e o MySql.EntityFrameworkCore 8.0.2
:
Existem alguns caminhos, listarei três deles: (execute as instruções no diretório do projeto)
- Pelo .NET CLI:
dotnet add package MySql.Data --version 8.4.0
dotnet add package MySql.EntityFrameworkCore --version 8.0.2
- Pelo Package Manager:
PM> Install-Package MySql.Data -Version 8.4.0
PM> Install-Package MySql.EntityFrameworkCore -Version 8.0.2
- Pela interface do Visual Studio:
Logo, em caso de sucesso, haverá as seguintes linhas no seu YourMvcProject.csproj
:
<ItemGroup>
...
<PackageReference Include="MySql.Data" Version="8.4.0" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.2" />
</ItemGroup>
Desta maneira, considerando que tudo tenha ocorrido bem, basta adicionarmos as configurações em nossa aplicação. Para isso, faremos alguns passos.
É questão de detalhe, mas muito importante quando o projeto é grande (e existem várias conexões de diferentes bancos) e principalmente quando se utiliza informações sensíveis, como a conexão ao banco ou dados de login (existem métodos mais eficazes e seguros para fazer isso, porém essa classe já é suficiente, mas não se acanhe em trazer alguma melhoria
:)
), pois caso eu não versione essa classe, os dados ficam encapsulados.
Segue a classe:
namespace YourMvcProject
{
public static class Configuration
{
public const string ConnectionString = "server=...;database=...;user=...;password=...;";
// a connection string no MySQL segue esse padrão
}
}
Essa é a classe derivada de
DbContext
do EF, que seria uma forma de abstrair o acesso ao banco de dados, uma forma muito interessante de integrar consultas ao banco sem necessariamente escrever uma string com o script SQL -- como é padrão no ADO.NET --, basta simplesmente utilizar o LINQ e recursos exclusivos do EF para isso!
Agora só é necessário sobrescrever o método OnConfiguring()
(ou substituir, caso já exista):
...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseMySQL(Configuration.ConnectionString);
// Como só há uma linha, podemos utilizar o Expression Body
...
Caso tenha utilizado scaffolding, será necessário editar a linha que apresentarei, pois este recurso adicionar a Connection String para MS SQL Server (só em caso de está utilizando outro banco de dados, como venho mostrando)
Basta adicionar (ou editar) a seguinte linha:
//...
"ConnectionStrings": {
"DefaultConnection": "server=...;database=...;user=...;password=..."
}
//...
Por fim, só basta injetar o contexto do banco na aplicação propriamente, havendo duas maneiras para isso:
- Com a definição da Connection String em
appsettings.json
:
...
builder.Services
.AddDbContext<YourMvcProjectContext>(options =>
options.UseMySQL(builder.Configuration.GetConnectionString("DefaultConnection") ??
throw new InvalidOperationException("Connection string 'DefaultConnection' not found."),
opt => opt.MigrationsAssembly("YourMvcProject"))
);
...
- Ou com
Configuration.ConnectionString
:
...
builder.Services
.AddDbContext<YourMvcProjectContext>(options =>
options.UseMySQL(Configuration.ConnectionString ??
throw new InvalidOperationException("Connection string not found."),
opt => opt.MigrationsAssembly("YourMvcProject"))
);
...
Compile a aplicação e corrija os potenciais erros que possa aparecer (qualquer dúvida, entre em contato), então continue o desenvolvimento da aplicação do projeto.
Só um acréscimo quanto a criação de migrações e atualização do contexto do banco de dados: como no curso se utiliza o terminal do gerenciado de pacotes no Visual Studio, não serão os mesmos comandos no terminal padrão para quem utilizar o Visual Studio Code.
Então, será necessário adicionar uma ferramenta adicional, o dotnet ef
; com este comando, podemos gerenciar o EF pelo CLI.
Começaremos instalando essa ferramenta:
dotnet tool install --global dotnet-ef
dotnet ef
O último comando apresenta a interface padrão do CLI como verificação da instalação.
Feito isso, basta seguir tais comandos:
Criação de Migrations
dotnet ef migrations add Initial
que equivale a:
Add-Migration Initial
Atualização do Banco de Dados
dotnet ef database update Initial
que equivale a:
Update-Database Initial
O último ponto que tenho a dizer, é sobre as configurações de injenção de dependência e entre outras configurações adicionais no ASP.NET, que desde o .NET 6 ocorre na classe Program.cs
não havendo mais a necessidade de uma classe intermediária de configurações -- pelo menos, em caso não tão complexos/extensos --, a classe Startup.cs
.
Seria interessante ter classes à parte para injetar muitas configurações e dependências (ou utilizando extension methods) para justamente evitar que a classe
Program.cs
se torne muito carregada.Isto é, reinserir a classe
Startup.cs
. Mas quando de fato se ver como necessário fazer isso.
Os quatro serviços criados durante o projeto (assim como o serviço que eu criei, o GitHubService.cs
), não diferem tanto do que foi mostrado pelo Nélio, mas é necessário ter atenção aonde adicionar as referências aos serviços na classe Program.cs
. Como estamos falando de injetá-los na aplicação, precisamos adicioná-los ao contexto logo após criar o builder
:
var builder = WebApplication.CreateBuilder(args);
// other services...
// Add data service for seeding
builder.Services.AddScoped<SeedingService>();
// Add seller service to the scope
builder.Services.AddScoped<SellerService>();
// Add department service to the scope
builder.Services.AddScoped<DepartmentService>();
// Add sales record service to the scope
builder.Services.AddScoped<SalesRecordService>();
// Add GitHub profile service to the scope
builder.Services.AddScoped<GitHubService>();
var app = builder.Build();
Já no caso da classe SeddingService.cs
, a sua configuração é um tanto diferente do que fora mostrado pelo Nélio -- exceto pela sua injeção, que é da mesma maneira dos outros serviços, como é mostrado anteriormente --, sendo necessário criar um escopo para aí sim chamar o método .Seed()
:
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var seedingService = services.GetRequiredService<SeedingService>();
seedingService.Seed();
}
Foi um tanto complicado achar uma solução para este último, então recomendo olhar a documentação do ASP.NET sobre injeção de dependências.
Caso seja mais interessante ao seu caso, pode adicionar uma classe Startup.cs
-- na verdade, o nome que lhe for adequado --, como anteriormente dito, e adicionar o código necessário para segregar as configurações de serviços e tudo mais da classe Program.cs
.