InvalidOperationException: Unable to resolve service for type '(プロジェクト名).(DbContext名)' while attempting to activate '(RazorPagesモデル名)'. エラーが発生しページが表示できない - C#

ASP.NET CoreでEntity Framework Coreを利用すると InvalidOperationException: Unable to resolve service for type '(プロジェクト名).(DbContext名)' while attempting to activate '(RazorPagesモデル名)'. エラーが発生しページが表示できない現象と対処法を紹介します。

現象

Entity Framework Coreを利用したRazorPagesを作成し、ページにアクセスすると、以下のエラーが発生しページが表示できない状態になります。
エラーメッセージ
InvalidOperationException: Unable to resolve service for type '(プロジェクト名).(DbContext名)' while attempting to activate '(RazorPagesモデル名)'.

エラー例

エラーメッセージ
InvalidOperationException: Unable to resolve service for type 'EntityFrameworkCoreRazorPages.MyDbContext' while attempting to activate 'EntityFrameworkCoreRazorPages.Pages.PageCreateModel'.

原因

RazorPagesのページモデルクラスのコンストラクタで、DbContextのインジェクションが記述されていますが、 プログラムの初期化時にDbContextのインジェクション処理を実行していないため、名前解決ができずエラーが発生します。
    private readonly EntityFrameworkCoreRazorPages.MyDbContext _context;

    public PageCreateModel(EntityFrameworkCoreRazorPages.MyDbContext context)
    {
        _context = context;
    }

対処法

Program.csファイルでDbContextのインジェクション処理を追加します。
Program.cs (修正前)
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();

app.Run();

Program.csにAddDbContextを追加します。
Program.cs (修正後)
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<EntityFrameworkCoreRazorPages.MyDbContext>();
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();

app.Run();

修正後のプログラムコード

Program.cs
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<EntityFrameworkCoreRazorPages.MyDbContext>();
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();

app.Run();
PageCreate.cshtml (Razor Pages)
@page
@model EntityFrameworkCoreRazorPages.Pages.PageCreateModel

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>PageCreate</title>
</head>
<body>

<h4>MyTable1Rec</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="MyTable1Rec.Name" class="control-label"></label>
                <input asp-for="MyTable1Rec.Name" class="form-control" />
                <span asp-validation-for="MyTable1Rec.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="MyTable1Rec.Category" class="control-label"></label>
                <input asp-for="MyTable1Rec.Category" class="form-control" />
                <span asp-validation-for="MyTable1Rec.Category" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="MyTable1Rec.Code" class="control-label"></label>
                <input asp-for="MyTable1Rec.Code" class="form-control" />
                <span asp-validation-for="MyTable1Rec.Code" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="MyTable1Rec.Price" class="control-label"></label>
                <input asp-for="MyTable1Rec.Price" class="form-control" />
                <span asp-validation-for="MyTable1Rec.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
</body>
</html>
PageCreate.cshtml.cs (ページモデルクラス)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using EntityFrameworkCoreRazorPages;

namespace EntityFrameworkCoreRazorPages.Pages
{
    public class PageCreateModel : PageModel
    {
        private readonly EntityFrameworkCoreRazorPages.MyDbContext _context;

        public PageCreateModel(EntityFrameworkCoreRazorPages.MyDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public MyTable1Rec MyTable1Rec { get; set; } = default!;
        

        // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
        public async Task<IActionResult> OnPostAsync()
        {
          if (!ModelState.IsValid || _context.MyTable1 == null || MyTable1Rec == null)
            {
                return Page();
            }

            _context.MyTable1.Add(MyTable1Rec);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}
_ValidationScriptsPartial.cshtml
<environment names="Development">
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment names="Staging,Production">
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.17.0/jquery.validate.min.js"
            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator"
            crossorigin="anonymous"
            integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js"
            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
            crossorigin="anonymous"
            integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds">
    </script>
</environment>
MyDbContext.cs (DbContextクラス)
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace EntityFrameworkCoreRazorPages
{
  public class MyDbContext : DbContext
  {
    public DbSet<MyTable1Rec> MyTable1 { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
      options.UseSqlServer("(DB接続文字列)");

    }
  }
}

実行結果

Program.csを修正するとページが正しく表示される動作になります。

補足:Program.csでDbContextOptionsを設定する場合

Program.csファイルのAddDbContextでオプションを設定する場合は、DbContextクラスのコンストラクタを以下に変更します。
Program.cs
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<EntityFrameworkCoreRazorPages.MyDbContext>(
  options => options.UseSqlServer("(DB接続文字列)")
  );
var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();

app.Run();
MyDbContext.cs
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace EntityFrameworkCoreRazorPages
{
  public class MyDbContext : DbContext
  {
    public DbSet<MyTable1Rec> MyTable1 { get; set; }

    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }
  }
}
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-12-18
作成日: 2022-12-17
iPentec all rights reserverd.