Skip to content

Web API - .NET 5-ről .NET 6-ra átállás

Published: at 00:00

Most, hogy megjelent a .NET 6 érdemes a folyamatban lévő, vagy meglévő .NET 5-ös projektek migrálásán elgondolkodni. Nézzük meg mivel is jár ez valójában!

Projekt file (csproj)

Az ötös projektek esetén is már a meglévő SDK projekt fájl van. Ennek elején az itt látható bejegyzés található.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
   ...

</Project>

Igazából az egyetlen fontos dolog, amin változtatni kell, hogy a TargetFramework értékét kell átírni net6.0 értékre. És igen ennyi az egész! Amire még szükség lehet az a használt csomagok frissítése. Én még hozzá tettem az ImplicitUsings és a nullable referenciák használatának bekapcsolását.

<Project Sdk="Microsoft.NET.Sdk.Web">
	
	<PropertyGroup>
		<TargetFramework>net6.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>
	...

</Project>

A target framework beállítás még a projecten jobb klikk Propertiesre kattintás után is megváltoztatható:

Továbbiak (program.cs és startup.cs)

Ez a lépés teljesen opcionális már. A korábbi hosting model továbbra is támogatott! Az új hosting modellnek (minimal hosting model) köszönhetően nem kell feltétlenül két osztály ahhoz, hogy a webalkalmazásunkat működésre bírjuk. A kódmennyiség csökkentésében még segítségünkre lesz a top-level statements és a global using (a korábban beállított implicit usings használatával). Ezekkel könnyen egyesíthetjük a program.cs és startap.cs fájlunkat és terjedelemre is kisebb lesz. Bemásoltam ide egy példa projekt két említett fájljának tartalmát:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>()
                .UseSerilog((hostContext, loggerConfiguration) =>
                {
                    loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration, "ExampleApiProjectLogging");
                });
            });
}
public class Startup
{
    public ILifetimeScope AutofacContainer { get; private set; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Example.ApiProject", Version = "v1" });
        });
        services.AddDbContext<ExampleApiProjectDbContext>(options =>
        {
            options.UseSqlServer(
                Configuration.GetConnectionString("ExampleApiProjectConnection"),
                sqlOptions => sqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", "dbo")
            );
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseMiddleware<ExceptionHandlerMiddleware>();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Example.ApiProject v1"));

            app.UseCors(
                options => options.WithOrigins("http://localhost:4200")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
            );
        }

        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        if (env.IsDevelopment())
        {
            app.UseSpa(spa =>
            {
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            });
        }
        else
        {
            app.UseDefaultFiles();
            app.UseSpaStaticFiles();
        }
        AutofacContainer = app.ApplicationServices.GetAutofacRoot();
    }

    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterModule(new ExampleApiProjectModule());
    }
}

Ezek összesen usingok nélkül is 95 sort tettek ki, usingokkal 100 felett van összesen. Alakítsuk át az új formára és nézzük meg mi lesz belőle.

Pár információ még előtte:

Elsőnek a program.cs fájlt alakítsuk át:

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new ExampleApiProjectModule()));
builder.Host.UseSerilog((hostContext, loggerConfiguration) =>
{
    loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration, "ExampleApiProjectLogging");
});

var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);

var app = builder.Build();

startup.Configure(app, app.Environment);

app.Run();

A top-level statements miatt nem szükséges névtér és osztály neki, szóval csak szabadon lehet script szerűen írni a kódot. Ezután amennyiben szeretnénk akár a startup osztályban található kódokat is átemelhetjük és akkor egy ilyen eredményt kapunk:

using Autofac;
using Autofac.Extensions.DependencyInjection;
// ...
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using Serilog;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new ExampleApiProjectModule()));
builder.Host.UseSerilog((hostContext, loggerConfiguration) =>
{
    loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration, "ExampleApiProjectLogging");
});

builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Example.ApiProject", Version = "v1" });
});

var connectionString = builder.Configuration.GetConnectionString("ExampleApiProjectConnection");
builder.Services.AddDbContext<ExampleApiProjectDbContext>(options =>
{
    options.UseSqlServer(
        connectionString,
        sqlOptions => sqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", "dbo")
    );
});

var app = builder.Build();
    app.UseMiddleware<ExceptionHandlerMiddleware>();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Example.ApiProject v1"));

    app.UseCors(
        options => options.WithOrigins("http://localhost:4200")
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials()
    );
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

if (app.Environment.IsDevelopment())
{
    app.UseSpa(spa =>
    {
        spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
    });
}
else
{
    app.UseDefaultFiles();
    app.UseSpaStaticFiles();
}

app.Run();

Kaptunk egy 70+ soros fájlt using résszel együtt, viszont most minden ömlesztve van kissé. Lehet még finomítani a dolgon meg az sem biztos, hogy mindenkinek ilyen nagy a startup része. Ez már ízlés kérdése, hogy kinek melyik változat tetszik jobban.


Previous Post
Entity Framework Core 6 - DateOnly, TimeOnly
Next Post
Git - törölt fájl visszaállítása