見出し画像

99.の続きの顛末 ~ コンテンツが古すぎる(涙)

前回の記事                        次回の記事

はじめに

前回は、ASP.NET Core 2.0 をベースに説明が書かれた

認可によって保護されたユーザー データを使って ASP.NET Core アプリを作成する | Microsoft Learn

を参考に、紹介されているとっかかりのサンプルを最新の ASP.NET Core 8.0 で書き換えてみました。それを受けて今回は、

ASP.NET Core での Razor ページ認可規則 | Microsoft Learn

にトライしようと思っていたのですが…
古すぎ―!
前回説明したように、プロジェクトのフォルダー構成もページ構成もガラッと変わっているので、これは、Microsoft Learn のフィードバック機能で、新しい説明に変えてください、とコメントして終わりにすることにしました。
期待していた読者がいたとしたら、大変申し訳ないです。

…と、これで終わりにすると、とても中途半端なので、幾つか、最新の ASP.NET Core のアーキテクチャの特徴や、この手の技術ドキュメントの書き方について書いていくことでお茶を濁すことにします。

ASP.NET Core が提供する権限管理機構

ASP.NET Core が提供する権限管理機構は、

  • ユーザー(Identity)認証

    • 独自の”ユーザー”管理をする場合は、Entity Framework Core と組み合わせて、ユーザー名、パスワード、メールアドレスを格納する RDB と連携して、認証、認証の確認ができる

    • OpenID を使えば、Microsoft Account、Google Account 等の認証機構が使える

    • ログインの状態が管理できる

      • ログインユーザーだけが閲覧できるページなど、権限設定ができる

  • ロールベースの権限管理

    • アドミニストレータ、管理者、一般ユーザー等のロールを作り、ユーザーがどのロールを持つか、管理できる

    • ロールとユーザーの対応付けには、RDB 等による保持・閲覧機構が必要

    • ロールごとに、閲覧できるページなど、権限設定ができる

というもの。権限設定は、開発プロジェクトの

  • ファイルごと

  • フォルダーごと

に設定できる(らしい ~ 全部実際に確認していないので)。

必要な機能の組込み

上のリストの機能の組込みは、Program.cs で、

var builder = WebApplication.CreateBuilder(args);

// Add Cookie Policy
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy= SameSiteMode.None;
});

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews();

// https://learn.microsoft.com/ja-jp/aspnet/core/security/authorization/razor-pages-authorization?view=aspnetcore-8.0
builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizePage("/Contact");
    options.Conventions.AuthorizeFolder("/Private");
    options.Conventions.AllowAnonymousToPage("/Private/PublicPage");
    options.Conventions.AllowAnonymousToFolder("/Private/PublicPages");

    options.Conventions.AuthorizeAreaFolder("/Identity", "/Manage");
});

// obsolute
// builder.Services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_2);
var app = builder.Build();

というように、アプリケーションの builder を作って、アプリケーションが提供するサービス群(builder.Services)を設定(Configure<YYY>)したり、追加(AddXXX<YYY>)したりして、最後に、Build() method をコールして、設定・追加した機能の初期設定を完了する、という流れで行っています。この過程で、具体的な実装を持っている class を指定して、Dependency Injection で、その実装を動かす、という仕組み。

その後、個別の機能を使う(UseXXX)ことを宣言して、追加したサービス機能に対する追加設定や初期化を、

using(var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    try
    {
        var context = services.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
        await SeedData.Initialize(services, "not used");
    }
    catch(Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred seeding the DB.");
    }   
}

のように、CreateScope method で行うようになっています。
最後に、

app.Run();

で、設定・機能の追加をしたアプリケーションが動き出す、という仕組み。

Dependency Injection

ちなみに、Dependency Injection とは、誰かが作ったフレームワークをコアにアプリケーションを動かすときに、正にその実行時に、ユーザーのカスタム実装コードを注入するような様を言います。フレームワーク設計者は、ユーザーがどんな風にそのフレームワークを使うか、そのすべてを想定することは不可能なので、特定の分野のアプリケーションを動かすのに必ず必要な基本機能と、処理の流れの骨格だけを、フレームワークとして実装し、フレームワークライブラリを一切変えずに、ユーザーのコードを注入できる仕組みを入れます。オブジェクト指向プログラミングの場合は、フレームワーク側から呼びたい method 一式を宣言した interface を定義しておき、その interface にだけ依存するようなコードとしてフレームワークライブラリを実装しておきます。ユーザー側は、既にある interface を実装する class を作るので、フレームワーク側が想定している method 一式が存在することが、保証されます。C++ や C# は Template の機構も使います。

例えば、

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

の AddEntityFrameworkStores method は、

public static IdentityBuilder AddEntityFrameworkStores<TContext>(this IdentityBuilder builder) where TContext : DbContext
{

こんな風に定義されていて、<TContext> は、 where TContext : DBContext つまり、DBContext を実装、あるいは、継承する class という縛りが定義されています。ApplicationDbContext class の宣言を調べてみると、

    public class ApplicationDbContext : IdentityDbContext
    {

で、IdentityDbContext の宣言を辿っていくと、

public abstract class IdentityUserContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken> : DbContext

と、DbContext を継承していることが分ります。
ちなみに、DbContext は、EntityFrameworkCore で interface が宣言されていて、ASP.NET Core 側は、安心して、その DbContext に宣言された method、property が利用可能というわけ。

読者の中で、再利用性と拡張性の高いフレームワークライブラリを作りたい人がいれば、この仕組みを活用してみましょうね。

程好い技術ドキュメントってどんなん?

う~む。。。古いバージョンを元にしているだけが、ASP.NET Core での Razor ページ認可規則 | Microsoft Learn が判り難い理由ではない気がします。
単に文句言うだけというのは、大人のやることではないので、こうしたら良いのでは、という提言形式にすることにします。
フレームワークの使い方を説明する場合、

  1. そのフレームワークを使うと良い場面

  2. その場面に必要な諸機能の紹介

  3. フレームワークがカバーする機能

    1. フレームワークが想定するデータモデル

    2. フレームワークが提供する基本的機能部品

    3. フレームワークがカバーする制御の骨格

  4. フレームワークを使ったアプリケーションが出来上がったときの全体像

    1. フォルダー構成

    2. ファイル構成

    3. 固定部分とユーザーが弄れる部分

  5. ユーザーが機能を拡張する時のパターン

  6. フレームワークに付随するツールキットの使い方の具体的な手順

こんな流れで書かれていると、いいんじゃないかと。特に、細かい手順の解説の前に、アプリケーションが出来上がったときの全体像と、機能とフォルダー・ファイルとの対応付けの説明があると、今回のような昔のバージョンで作られたファイルセットを新しいバージョンに移行する時に、とても役立ちます。もちろん、旧バージョンと新バージョンの違いを説明するドキュメントを作るべきなのは言うまでもありませんが。ただ、筋がいいフレームワークは、バージョンアップの過程で、あるべき姿に近づいていくもので、より直観的に使えるようになっていくので、違いに関するドキュメントを詳しく書くことに注力するより、よりアーキテクチャ的に素性が良いフレームワークに改編していく方に労力を費やした方がよろしい。

リストの中に、”データモデル”という言葉がありますが、これは、”Art of Conceptual Modeling”で解説しているようなオントロジー的なデータモデルを指します。
考えてみてくださいね。フレームワークの説明は、”言葉”で行われます。その”言葉”の意味が分からなければ、どんなに丁寧に詳しく書かれていたとしても、説明文は理解できませんよね。
8. 概念モデルの言語論理学からの考察 ~ Frege、Russel、Wittgenstein|Knowledge & Experience (note.com) で解説している通り、単語の説明の羅列があるだけでは、言葉の意味は確定しないので、やはり、単語・単語で指示された対象が持つ性質、及び、単語間の意味的つながりを記述しているデータモデルが必要ってこと。

最後に

以上で、今回は終わりです。こういう中途半端な記事を100回というきりの良い回にしたくなかったんだよね。。。

よく”言霊”っていうけれど、オカルトじゃあるまいし、言った言葉がそのまま現実の物理現象を変えることはありません。せいぜい、空気を震わせるだけ。しかし、言葉は、人の脳には影響を与えて、それに伴いその人が行動することで、現実世界が変わっていくことは間違いないと。数学なら負×負は正になるけど、言葉は、人間の脳内では、負の言葉+負の言葉で、2倍の負になるそう。これ、聞いた側だけでなく言った側の脳内でもそうらしい。人を呪わば穴二つ、っていうのもこれによるらしい。負の思念は、人の心をむしばんでいくので、厄介。
モノは言いようなので、なるべく正の良い言葉で、こうすると良くなるよ的な言葉を紡ぐ努力を続けるのが大事だなぁ…と思う今日この頃です。

次回の内容は現在検討中でございまする。。。

ここから先は

0字

2022年3月にマイクロソフトの中の人から外の人になった Embedded D. George が、現時点で持っている知識に加えて、頻繁に…

この記事が気に入ったらチップで応援してみませんか?