質問: ### 前提・実現したいこと 認証ありのASP.NET Core Razor Pagesをで、スキャフォールディングにてPageを作成したいです。 ### 再現手順 #### 認証ありRazor Pagesアプリの作成 VisualStudioで新規プロジェクト>ASP.NET Core Webアプリケーション>Webアプリケーション(認証あり/個別のユーザーアカウント)で作成 パッケージマネージャーコンソールで ``` Add-Migration Initial Update-Database ``` この状態で起動して、ログインなどの動作は確認しました。 #### スキャフォールディングの実行 Microsoft.EntityFrameworkCore.Sqliteをnugetで追加 以下のファイルを追加 Models>Person.cs ``` public class Person { public int PersonId { get; set; } public string Name { get; set; } } ``` Pages>Personsフォルダで追加>新規スキャフォールディングアイテムの追加>Entity Frameworkを使用するRazorページ(CRUD) * モデルクラス: Person.cs(上記モデル) * データコンテキストクラス:既存のContextは選択できず、【+】ボタンから新規作成 ![新規スキャフォールディングアイテムの追加](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/939d5bc478ac33fb33ce1ce8175c3729.png) パッケージマネージャーコンソールで以下の操作をするとエラーメッセージが表示され、Migrationも作成されません。 ``` Add-Migration AddPerson ``` More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands. Migrationができていないので、当然かもしれませんが、Personsのページにアクセスしてもエラーします。 `https://localhost:44386/Persons` ``` A database operation failed while processing the request. SqlException: Cannot open database "RazorPageAuthScafffoldContext-86510494-657f-4c38-bf76-28d0f480abea" requested by the login. The login failed. Login failed for user 'xxxxxxxxxx'. Use migrations to create the database for RazorPageAuthScafffoldContext In Visual Studio, use the Package Manager Console to scaffold a new migration and apply it to the database: PM> Add-Migration [migration name] PM> Update-Database Alternatively, you can scaffold a new migration and apply it from a command prompt at your project directory: > dotnet ef migrations add [migration name] > dotnet ef database update ``` なお、同様の手順を認証のないプロジェクトテンプレートで行った場合は問題なくできました。 ### 試したこと IdentityASP.NET Core プロジェクトでのスキャフォールディング | Microsoft Docs 上記ページを参考にしたのですが、[ **Identity** add] 自体の表示がなかったです。 > > [ **Add スキャフォールディング**] ダイアログボックスの左ペインで、[ **Identity** add] を選択 > > > #### 解決後追記 解決後に自身でわかったことがあるので、追記します。 「IdentityASP.NET Core プロジェクトでのスキャフォールディング」の項目は、ログインや登録画面をスキャフォールディングで作成することを説明しています。 そして、そのメニューは「ID」という情報量がすくない選択肢で実行されます。 名前の割に、2要素認証画面などなどの、すごい量のファイル数が作られます。 ### 補足情報(FW/ツールのバージョンなど) #### 環境 Windows 10 1909 Visual Studio 2019 ver. 16.6.2 .NET Core 3.1 #### 筆者のレベル C#を用いたデスクトップアプリケーションの開発経験(WPF)はあります。 C#言語自体はおおよそ理解しているつもりです。 WebアプリケーションはC#も含めて、初心者です。 ASP.NET Core3入門は全て実行してみました。
回答: > > Use the '-Context' parameter > > > と言われている通りにしてみてください。ASP.NET Core Identity 用の DbContext クラスと質問者さん独自の DbContext クラスのどっちか分からないということでエラーになっています。 **【追記】** 下の 2020/06/12 10:41 の私のコメントで、「コメント欄では画像が貼れないコードが書けないので、後で回答欄に追記します」と書きましたが、それを以下に追記します。 > > 新しく生成したDbContextを直接継承したアプリケーションデータコンテキストにPersonクラスのデータベースが含まれているようです。 > > > 「アプリケーションデータコンテキスト」とは何ですか? Visual Studio でプロジェクトを作成する際、認証に「個別のユーザーアカウント」を選んでコードを生成すると Data/ApplicationDbContext.cs というファイルに public class ApplicationDbContext : IdentityDbContext というクラスが生成されますが、それのことですか? !イメージ説明 そうだとすると、そのファイルに「Personクラスのデータベースが含まれている」などということはあり得ないと思うのですが? そうではなくて、先に「個別のユーザーアカウント」用(ASP.NET Core Identity 用)に生成されたデータベース内に、Person テーブルが追加で生成されたということですか? であれば、それはやり方によってはあり得ますし、問題ないです。 > > 元々あった、IdentityDbContextを継承したアプリケーションデータコンテキストが選択肢に表示されなかったのは何故でしょうか? > > > そこは自分の環境でも同じで選択肢には現れません。理由は分かりません。想像ですが(なのでハズレかも)、DbContext クラスを継承したものしか選択肢には表示されないのではないかと思います。 そもそも ApplicationDbContext をスキャフォールディングに使う(ApplicationDbContext を使って Controller / View を作る)ということはない(できない)はずで、現れなくても何の問題もないと思いますけど。 > > また、2つのデータコンテキストは統合してしまってもよいのでしょうか? > > > データベースは同じ(ただし、テーブルは別)でも問題ないですが、コンテキストクラスは別にしないとダメ・・・というか、そもそも ApplicationDbContext クラスと PersonContext クラスの統合などということはやろうと思ってもできないと思いますけど? 上の画像の ApplicationDbContext クラスを見たらそんなことは考えもしないと思うのですが。 今回、作り方に問題があると思います。 Visual Studio でプロジェクトを作成する際、認証に「個別のユーザーアカウント」を選んでコードを生成すると上の画像の ApplicationDbContext クラスのコードが自動生成されるだけでなく、appsettings.json に接続文字列 "DefaultConnection" が設定され、それは LocalDB に接続するようになっています。 !イメージ説明 さらに、Startup.cs には以下の画像のように、ApplicationDbContext については SQL Server を利用して接続文字列 "DefaultConnection" で接続するように指定されます。 !イメージ説明 その結果、パッケージマネージャーで、 ``` Add-Migration Initial Update-Database ``` とすると、上の接続文字列の Database に指定される名前で LocalDB に ASP.NET Core Identity 用のデータベースが生成されます。 その状態から、Person クラスを定義して、それ用のデータベースと、CRUD を行うための Controller / View をスキャフォールディング機能で生成しようとしたのが今回の質問の話ですよね。 であれば、まず、 > > Microsoft.EntityFrameworkCore.Sqliteをnugetで追加 > > > が間違い・・・とまでは言えないものの、そのまま SQL Server (LocalDB) を使うデフォルトの設定を利用すべきです。何が何でも SQLite を使わなければならないという事情があれば話は別ですが、そうではないのですよね? 次に Person クラスだけ定義して、そこから一気にスキャフォールディング機能でコンテキストクラスとその設定およびデータベースの生成まで自動でやろうとしたところ。 それで何が起こるかがすべて把握できていれば話は別ですが、そうでなければ何が起こったのか今回のように訳が分からなくなるので止めた方がよさそうです。 まず自力で以下のところまでやることをお勧めします。 (1) PersonContext クラスの作成 以下のような感じ ``` using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using MvcCoreApp.Models; namespace MvcCoreApp.Data { public class PersonContext : DbContext { public PersonContext(DbContextOptions options) : base(options) { } public DbSet Person { set; get; } } } ``` (2) Startup.cs への追加 appsettings.json にある既存の接続文字列 "DefaultConnection" を使う設定になっていますが、そのようにすると ASP.NET Core Identity 用に作られたデーターベースに Person テーブルが追加されます。別のデーターベースにしたい場合は別の接続文字列を appsettings.json に追加してそれを設定します。 ``` services.AddDbContext(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"))); ``` (3) Add-Migration, Update-Database の実行 コンテキストクラス名を指定しなけらばならないのは先に学んだとおりです。 (4) 結果の確認 !イメージ説明