WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

中間テーブルへのナビゲーションプロパティ

by WebSurfer 3. May 2023 15:32

多対多のリレーションシップを関連付ける中間テーブルへのナビゲーションプロパティ定義の問題で ASP.NET Core MVC での Create, Edit に失敗するのにハマって悩みました。またハマることがないよう備忘録として書いておきます。

エンティティ クラス

上の画像は Microsoft のドキュメント「チュートリアル: ASP.NET MVC Web アプリでの EF Core の概要」のもので Enrollment が中間テーブルです。チュートリアルは Student テーブルの CRUD 操作を行う ASP.NET Core MVC アプリを作成するもので、これをこの記事の例に使います。

Visual Studio 2022 のテンプレートを使ってターゲットフレームワーク .NET 6.0 以降でプロジェクトを作ると、デフォルトでプロジェクト全体で「Null 許容」オプションが有効にされます。

「Null 許容」オプションが有効にされていると、チュートリアルの Student クラスの定義では LastName, FirstMiddleName, Enrollments プロパティ に対しては "null 非許容のプロパティ 'xxxxx' には、コンストラクタの終了時に null 以外の値が入っていなければなりません" という警告が出ます。

その警告を回避するのに、以下のように = null!; を追加したのですが、ナビゲーションプロパティ Enrollments に対してそれはダメでした。ASP.NET Core MVC アプリによる CRUD 操作のうち Create, Edit に失敗します。

public class Student
{
    public int ID { get; set; }
    public string LastName { get; set; } = null!;
    public string FirstMidName { get; set; } = null!;
    public DateTime EnrollmentDate { get; set; }

    // これはダメ。ASP.NET Core MVC での Create, Edit に失敗する
    public ICollection<Enrollment> Enrollments { get; set; } = null!;
}

なぜ失敗するかと言うと、上の定義の場合 Enrollments が ModelStateDictionary に含まれるようになり、値が null になるので ValidationState が Invalid となってしまうからのようです。下の画像を見てください。結果、ModelSate.IsValid が false になって SaveChangesAsync メソッドがスキップされてしまいます。

デバッグ結果

チュートリアルの次のステップ「チュートリアル: CRUD 機能を実装する - ASP.NET MVC と EF Core」で、Edit アクションメソッドに TryUpdateModelAsync<T> メソッドを使う方法が紹介されていますが、それも失敗します。

解決策は、リバースエンジニアリングで既存の同等なデータベースから生成されるコードをまねて、Enrollments プロパティを以下のようにすることだと思います。

public ICollection<Enrollment> Enrollments { get; } = 
                                          new List<Enrollment>();

そうすれば、下の画像の通り ModelStateDictionary には Enrollments は含まれなくなります。Edit アクションメソッドに TryUpdateModelAsync<T> メソッドを使った場合も期待通りの結果となります。

デバッグ結果

Tags: , , ,

CORE

dotnet dev-certs https コマンドについて

by WebSurfer 30. March 2023 21:43

dotnet dev-certs https コマンドについて調べたことを備忘録として残しておきます。

dotnet dev-certs コマンド

dotnet dev-certs コマンドは、Microsoft のドキュメント dotnet dev-certs に書いてありますように、開発用のサーバー証明書の作成・管理を行うためのツールです。

具体的には、フレンドリ名が ASP.NET Core HTTPS development certificate という自己署名証明書を作成・管理するツールです。その証明書を使って、ASP.NET Core Web アプリの開発中に、Web サーバーの Kestrel がブラウザなどのクライアントと HTTPS 通信ができるようになります。

(注: IIS Express でホストする場合は IIS Express Development Certificate というフレンドリ名の証明書が使用されます。このスレッドの話は関係ないので注意してください。)

このコマンドの実行によって証明書マネージャーに表示される証明書がどのようになるか、証明書がないときアプリを Kestrel で動かそうとするとどうなるかも以下に合わせて書いておきます。

(1) 初期状態

Visual Studio を開発に使っていれば自力で dotnet dev-certs コマンドを打って証明書を作る必要はなく、Visual Studio がコマンドを使って必要な証明書を生成してくれます。下の証明書マネージャーの画像がその結果で、発行先が localhost となっているのが開発用サーバー証明書です。

開発用サーバー証明書

有効期限切れのものが含まれていますが (何年か Visual Studio で作業しているうちに追加されたものです)、作業していて支障はなかったのでそのままにしていました。

この中のフレンドリ名 ASP.NET Core HTTPS development certificate という証明書をすべて削除してから、新しく証明書を作成し、開発環境でそれを使って HTTPS 通信ができるようにします。

(2) dotnet dev-certs https --clean 実行

既存の証明書を削除するためコマンドラインから dotnet dev-certs https --clean を実行します。

コマンドを打つと下の画像の「ルート証明書ストア」というダイアログが出て削除してよいかが確認されるので[はい]をクリックします。(上の画像のように複数証明書がある場合は複数回ダイアログが出ます)

「ルート証明書ストア」ダイアログ

削除に成功するとコマンドラインに "HTTPS development certificates successfully removed from the machine." と表示され、証明書マネージャーの[個人]>[証明書]および[信頼されたルート証明書]>[証明書]にあったフレンドリ名 ASP.NET Core HTTPS development certificate の証明書はすべて削除されます。

(IIS Express 用の証明書 IIS Express Development Certificate にはこのコマンドは影響ありません)

この状態でコマンドラインから dotnet dev-certs https --check を実行すると "No valid certificate found." と表示されます。

(3) アプリの実行

証明書を削除した後、Visual Studio 2022 で Kestrel を使って ASP.NET Core Web アプリを実行すると「ASP.NET Core SSL 証明書を信頼する」というダイアログが出ます。

ASP.NET Core SSL 証明書を信頼する

[いいえ]を選択すると下の画像のダイアログが出て「Web サーバー 'MvcCore6App2' に接続できません。Web サーバーはもう実行されてません」というメッセージが表示されて終わってしまいます。

ダイアログ

コンソールを見ると以下の例外が出ていました。

Unhandled exception. System.InvalidOperationException: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.

(IIS Express 用の証明書 IIS Express Development Certificate には影響はありませんので、Visual Studio 2022 の設定を IIS Express を使うようにしてアプリを実行すれば上のような問題はありません)

(4) dotnet dev-certs https 実行

証明書を作成するためコマンドラインから dotnet dev-certs https を実行します。作成に成功すると "The HTTPS developer certificate was generated successfully." というメッセージが表示されます。

証明書マネージャーを見ると[個人]>[証明書]にフレンドリ名 ASP.NET Core HTTPS development certificate という証明書が追加されています。

証明書マネージャー

ただし、この時点では[信頼されたルート証明書]>[証明書]には ASP.NET Core HTTPS development certificate は存在しません。

この状態で上の (3) と同様にアプリを実行してみます。同じく「ASP.NET Core SSL 証明書を信頼する」というダイアログが出るので[いいえ]を選択すると、今度は InvalidOperationException 例外はスローされず、自己署名証明書を使った場合の警告がブラウザに表示されます。

プライバシーエラー

警告を無視して進めればブラウザにコンテンツの表示はできます。

(5) dotnet dev-certs https --check 実行

コマンドラインから dotnet dev-certs --check を実行しても証明書が発行されたかどうかを確認できます。発行されていると以下のようなメッセージが返ってきます。

A valid certificate was found: 8216607E62A7221B7EFEC3022C8AD599DC1728B1 - CN=localhost - Valid from 2023-03-28 13:07:39Z to 2024-03-27 13:07:39Z - IsHttpsDevelopmentCertificate: true - IsExportable: true
Run the command with both --check and --trust options to ensure that the certificate is not only valid but also trusted.

このコマンドは証明書の情報を確認するためだけのものです。証明書を作成することもなく、作成済みの証明書には何も影響しません。

(6) dotnet dev-certs https --trust 実行

上の (4) で発行した証明書を「信頼されたルート証明書」として登録するため、コマンドラインから dotnet dev-certs https --trust を実行します。

コマンドを入力すると、コマンドラインには "Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed if the certificate was not previously trusted. Click yes on the prompt to trust the certificate." というメッセージが表示され、下の画像のセキュリティ警告ダイアログが表示されます。

セキュリティ警告ダイアログ

[はい]をクリックして処理を継続します。成功するとコマンドラインには "Successfully trusted the existing HTTPS certificate." というメッセージが表示されます。

証明書マネージャーを見ると[信頼されたルート証明書]>[証明書]に ASP.NET Core HTTPS development certificate が追加されています。

証明書マネージャー

この後で Visual Studio からアプリを実行すれば証明書の問題はなくなり HTTPS 通信を使っての開発ができるようになります。

Tags: , , , ,

CORE

Blazor アプリで Bootstrap5 Modal の利用

by WebSurfer 11. March 2023 14:09

Blazor アプリで Bootstrap5 の Modal を使う方法を書きます。この記事では Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor Web Assembly を例に使います。(Blazor Server でもほぼ同じようにしてできます)

Blazor アプリで Bootstrap Modal

Bootstrap5 Modal の詳しい説明は Bootstrap のドキュメント「Modal (モーダル)」にあります。普通の html + css + javascript のページに Bootstrap5 Modal を組み込むなら、そのドキュメントから十分な情報が得られると思います。

JavaScript のメソッドを呼び出すのがいろいろややこしい Blazor アプリに、Bootstrap5 Modal を組み込むにはどうしたらいいかというのががこの記事のポイントで、それを以下に述べます。

Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor アプリには bootstrap.min.css v5.1.0 が組み込み済みです。ただし、それだけでは Modal は使えません。使うには bootstrap.js が必要なので同じバージョンのものを wwwroot 下に追加します。

加えて、JavaScript で Modal を表示するためのコードを含んだ外部スクリプトファイルを作成します。内容は以下の通りです。Bootstrap のドキュメント「Via JavaScript」を参考にしました。ファイル名は exampleJsInterop.js としています (名前は任意)。

window.showBootstrapModal = () => {
    // staticBackdrop は modal 表示する div 要素の id
    let divModal = document.getElementById('staticBackdrop');
    let myModal = new bootstrap.Modal(divModal);
    myModal.show();
}

Modal を表示するには、Bootstrap のドキュメント「Via data attributes」に書かれているように、表示に必要な属性を付与した button のような要素を使う方法もあります。その方法で良ければ、上のスクリプトファイル exampleJsInterop.js は不要です。ただし、その場合でも bootstrap.js は必要ですので注意してください。

bootstrap.js ファイルと exampleJsInterop.js ファイルを wwwroot 下に配置し、wwwroot/index.html にそのファイルへの参照を追加します。下の画像の赤枠を見てください。青枠は既存の bootstrap.min.css のものです。

外部スクリプトファイルの追加

Bootstrap5 は jQuery に依存していないそうですので jquery.js は不要です。(上の画像では jquery.js も追加されていますが、Bootstrap5 とは関係ない別の目的です)

Blazor Sever の場合、外部スクリプトファイル bootstrap.js と exampleJsInterop.js への参照を追加するのは Pages/_Layout.cshtml になります。そこだけが Blazor Web Assembly と Blazor Server の違いです。

Pages フォルダ下に Razor コンポーネントを追加し、それに Bootstrap のドキュメント「Live demo」のコードをコピーします。それだけで[Launch static backdrop modal]ボタンをクリックすると Modal が表示されるようになります。

Blazor アプリで Bootstrap Modal

JavaScript で Modal を表示するには、外部スクリプトファイル exampleJsInterop.js の showBootstrapModal メソッドを呼び出してやります。それを含めた Razor コンポーネント全体のコードは以下のようになります。

[Via JavaScript]ボタンに設定した @onclick="ShowBootstrapModal" で @code 内の ShowBootstrapModal メソッドを呼び出し、その中の InvokeVoidAsync メソッドで showBootstrapModal メソッドを呼び出しています。

@page "/modal"
@inject IJSRuntime JSRuntime;

<PageTitle>Bootstrap Modal</PageTitle>

<!-- Modal -->
<div class="modal fade" 
    id="staticBackdrop" 
    data-bs-backdrop="static" 
    data-bs-keyboard="false" tabindex="-1" 
    aria-labelledby="staticBackdropLabel" 
    aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" 
                    id="staticBackdropLabel">
                    Modal title
                </h5>
                <button type="button" 
                    class="btn-close" 
                    data-bs-dismiss="modal" 
                    aria-label="Close">
                </button>
            </div>
            <div class="modal-body">
                ...
            </div>
            <div class="modal-footer">
                <button type="button" 
                    class="btn btn-secondary" 
                    data-bs-dismiss="modal">
                    Close
                </button>
                <button type="button" 
                    class="btn btn-primary">
                    Understood
                </button>
            </div>
        </div>
    </div>
</div>

<h1>Bootstrap Modal</h1>

<!-- Via JavaScript -->
<button type="button" class="btn btn-primary" 
    @onclick="ShowBootstrapModal">
    Via JavaScript
</button>

<br />
<br />

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" 
    data-bs-toggle="modal" 
    data-bs-target="#staticBackdrop">
    Launch static backdrop modal
</button>

@code {
    private async Task ShowBootstrapModal()
    {
        await JSRuntime
            .InvokeVoidAsync("showBootstrapModal");
    }
}

JavaScript のメソッドを呼び出す方法の詳細は Microsoft のドキュメント「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」に書かれていますので興味がありましたら読んでください。

Tags: , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  June 2023  >>
MoTuWeThFrSaSu
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

View posts in large calendar