質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.10%

認証ありのASP.NET Core Razor Pagesで新規スキャフォールディングに失敗します。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,381

score 15

前提・実現したいこと

認証ありの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は選択できず、【+】ボタンから新規作成

新規スキャフォールディングアイテムの追加

パッケージマネージャーコンソールで以下の操作をするとエラーメッセージが表示され、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入門は全て実行してみました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

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<PersonContext> options)
            : base(options)
        {

        }

        public DbSet<Person> Person { set; get; }

    }
}

(2) Startup.cs への追加

appsettings.json にある既存の接続文字列 "DefaultConnection" を使う設定になっていますが、そのようにすると ASP.NET Core Identity 用に作られたデーターベースに Person テーブルが追加されます。別のデーターベースにしたい場合は別の接続文字列を appsettings.json に追加してそれを設定します。

services.AddDbContext<PersonContext>(options =>
    options.UseSqlServer(
        Configuration.GetConnectionString("DefaultConnection")));

(3) Add-Migration, Update-Database の実行

コンテキストクラス名を指定しなけらばならないのは先に学んだとおりです。

(4) 結果の確認

イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/12 10:02

    ありがとうございます。無事に動きました。

    2点疑問があるので、もしご存知だったら、教えて下さい。
    新しく生成したDbContextを直接継承したアプリケーションデータコンテキストにPersonクラスのデータベースが含まれているようです。
    元々あった、IdentityDbContextを継承したアプリケーションデータコンテキストが選択肢に表示されなかったのは何故でしょうか?
    また、2つのデータコンテキストは統合してしまってもよいのでしょうか?

    キャンセル

  • 2020/06/12 10:41

    > 2点疑問があるので、もしご存知だったら、教えて下さい。

    コメント欄では画像が貼れないコードが書けないので、後で回答欄に追記します。

    キャンセル

  • 2020/06/12 15:35

    追加での疑問にも懇切丁寧に答えていただき大変ありがとうございます。

    > 「アプリケーションデータコンテキスト」とは何ですか?

    正確でない用語を使ってしまって申し訳ありません。
    質問の中のスキャフォールディングスクリーンショットの中にある「データコンテキストクラス」の選択肢に表示されるものです。

    > 何が何でも SQLite を使わなければならないという事情があれば話は別ですが、そうではないのですよね?

    はい、たんに入門書の手順ではスキャフォールディングの前にそう書いてあったから、程度の理由です。

    そして結局、Startup.csの`ConfigureServices()`内の新旧どちらも`services.AddDbContext<...>(options => options.UseSqlServer(...`となっていたので、Sqliteは使っていないようです。

    > まず自力で以下のところまでやることをお勧めします。

    了解しました。これからはその手順で行います。よくわからず、自動生成に頼りすぎるのは良くないですね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る