vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

【ASP.NET Core】【Entity Framework Core】【C#】 .NET 6から.NET 9に更新する

はじめに

この記事は C# Advent Calendar 2024 の第一日目の記事です。

なお以前.NET 5から.NET 6にアップグレードする記事を書いていましたね。

まるで成長していない…。

ともあれ、.NET 9リリースおめでとうございます👏。

.NET 9に更新する

とりあえず 以前と同じように .NET 9.0.0 に更新します。

パッケージを更新します。

  • Microsoft.EntityFrameworkCore ver.9.0.0
  • Npgsql.EntityFrameworkCore.PostgreSQL ver.9.0.1
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore ver.9.0.0
  • Microsoft.AspNetCore.Authentication.JwtBearer ver.9.0.0
  • Microsoft.EntityFrameworkCore.Design ver.9.0.0
  • NLog.Web.AspNetCore ver.5.3.15

コンパイルエラーがあれば直します。

なかったので終了ーーーーー。

.NET Coreから.NETになって以降、現在に至るまで基本的なコードでは破壊的な変更はないんですね~~。

…だとあまりにアレなので、もう少し見てみます。

DBマイグレーション時のエラーを無視

地味に困ったのがこれ。

Entity Framework CoreのDBマイグレーションの「dotnet ef database update」を実行すると、処理自体は正しく動作しているようなのに、下記のような例外が発生します。

Microsoft.Extensions.Hosting.HostAbortedException: The host was aborted.

結局キャッチするしか方法が見つけられませんでした。。

Program.cs

using System.Net;
using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using NLog;
using NLog.Web;
using UpgradeProjectSample.Books;
using UpgradeProjectSample.Models;
using UpgradeProjectSample.Users;
using UpgradeProjectSample.Users.Models;
using UpgradeProjectSample.Users.Repositories;

var logger = LogManager.Setup().LoadConfigurationFromFile("Nlog.config").GetCurrentClassLogger();

try
{
    var builder = WebApplication.CreateBuilder(args);
...
    builder.Services.AddDbContext<SampleContext>(options =>
        options.UseNpgsql(builder.Configuration.GetConnectionString("BookShelf")));
...
}
catch (Exception ex) when (ex is not HostAbortedException)
{
    logger.Fatal(ex, "Host terminated unexpectedly.");
}
finally
{
    LogManager.Shutdown();
}

ログの設定

ロガーとしてNLogを使っているのですが、設定のためのクラス、メソッドが変更されたようです。 (元のコードでも動きはしますが、deprecatedの警告が表示されます)

[Before] Program.cs

...
var logger = NLogBuilder.ConfigureNLog("Nlog.config").GetCurrentClassLogger();
try
{
    var builder = WebApplication.CreateBuilder(args);
    builder.Host.ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.SetMinimumLevel(LogLevel.Trace);
    })
    .UseNLog();
...

[After] Program.cs

...
// Nlog.configファイル読み込みのメソッドが変更された
var logger = LogManager.Setup().LoadConfigurationFromFile("Nlog.config").GetCurrentClassLogger();
try
{
    var builder = WebApplication.CreateBuilder(args);
    // builder.Host.ConfigureLoggingを使う必要がなくなった
    builder.Logging.ClearProviders();
    builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
    builder.Host.UseNLog();
...

WebApplicationBuilderとWebApplicationの変更

デフォルトだとProgram.csで呼ばれている、WebApplicationBuilderとWebApplicationでも変更がありました。

先ほどのbuilder.Host.ConfigureLoggingと同様、app.UseEndpointsも不要となりました。

[Before] Program.cs

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

[After] Program.cs

...
    app.MapControllers();
...

Primary Constructor

C# 12で追加されたPrimary Constructorも利用できます。

SampleContext.cs

using Microsoft.EntityFrameworkCore;
...
public class SampleContext(DbContextOptions<SampleContext> options) : DbContext(options)
{
...
}

DIでインスタンスを受け取って変数に代入するだけなら、切り替えてしまうのが良さそうです。 (コンストラクタ内でそれ以外の処理が必要になった場合が面倒ではありますが)

なおDIなどでPrimary Constructorの引数として渡されたインスタンスには、メンバ変数のようにアクセスはできるものの、クラスのメンバでないことから「this」をつけるとエラーになります。

BookController.cs

using UpgradeProjectSample.Books;
using UpgradeProjectSample.Books.Dto;
using UpgradeProjectSample.Models;
using UpgradeProjectSample.Users;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace UpgradeProjectSample.Controllers;
[Authorize(AuthenticationSchemes = UserTokens.AuthSchemes)]
public class BookController(IBookService bookService,
    ISearchBooks books) : Controller
{
    [Route("books/createsample")]
    public async Task<string> CreateSample(string name)
    {
        // 「this」をつけるとエラー
        await bookService.CreateSampleAsync(name);
        return "Create Sample";
    }
...

その他

ASP.NET Core 9から静的ファイル最適化して配置する「MapStaticAssets」が追加されました。

「UseStaticFiles」と同様に使えるものの、例えばシステム内の特定のディレクトリ以下のファイルを公開する、 などの場合は「UseStaticFiles」が必要になるなど、完全な置き換えにはならず、使い分けが必要なようです。

おわりに

前回の記事から3年が経過しても、基本的にはそのままのコードが動いてくれるのは大変ありがたいところです。

ただ、今回取り上げているサンプルがかなり簡単な機能しか実装できておらず、追加されたものの使えていない機能もたくさんあるんだろうなぁとは思うので、少しずつでも継続して試していきたいと思います。

C# Advent Calendar 2024、明日は@mylifewithviolinさんです。

よろしくお願いいたしますm(__)m