LoginSignup
3
2

More than 1 year has passed since last update.

ASP.NET Core Razor PagesでIAsyncPageFilterを実装する

Last updated at Posted at 2022-11-23

はじめに

ASP.NET Core MVC には、IActionFilterというインターフェースがあり、これを実装することで、要求処理パイプラインのアクション メソッドが呼び出される直前と直後に独自のコードを実行させることができます。
Razor Pagesでも似たようなIAsyncPageFilterインターフェース、 IPageFilterインターフェースが用意されています。

ここでは、非同期版のIAsyncPageFilterインターフェースの簡単な使い方を説明します。

なおこの記事で作成したソースコードはGitHuibで公開しています。
https://github.com/gushwell/IAsyncPageFilterSample

IAsyncPageFilterインターフェース

IAsyncPageFilterインターフェースには、以下の2つのメソッドがあります。

public interface IAsyncPageFilter : IFilterMetadata
{
   Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context);
   Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next);
}

OnPageHandlerSelectionAsyncメソッドは、Pageハンドラー メソッドが選択された後、モデル バインドが発生する前に非同期的に呼び出されます。

OnPageHandlerExecutionAsyncは、モデル バインドが完了した後、ハンドラー メソッドが呼び出される前に非同期的に呼び出されます。

IAsyncPageFilterを実装する

ここでは、簡単なアクセスログを出力するコードを書いてみます。

モデルバインディングでエラーになった場合もログを出力するようにOnPageHandlerSelectionAsyncメソッドでログを出力しています。

using Microsoft.AspNetCore.Mvc.Filters;

namespace WebAppSample;

public class MyAsyncPageFilter : IAsyncPageFilter
{
    private readonly ILogger _logger;
    public MyAsyncPageFilter(ILogger logger)
    {
        _logger = logger;
    }

    public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
    {
        await next.Invoke();
    }

    public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
    {
        var httpContext = context.HttpContext;
        var message = $"HttpType: {httpContext.Request?.Method}|Path :{httpContext.Request?.Path}\tUserAgent: {httpContext.Request?.Headers["User-Agent"].ToString()}\tPage: {context.HandlerInstance?.GetType().Name}\tHandler: {context.HandlerMethod?.MethodInfo?.Name}";
        _logger.LogTrace(message);
        return Task.CompletedTask;
    }

}

MyAsyncPageFilterをグローバルに組み込む

Program.csで、先ほど作成したMyAsyncPageFilterを組み込みます。

using WebAppSample;

var builder = WebApplication.CreateBuilder(args);

var logger = LoggerFactory.Create(config =>
{
    config.AddConsole();
    config.SetMinimumLevel(LogLevel.Trace);
}).CreateLogger("WebAppSample");

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.Filters.Add(new MyAsyncPageFilter(logger));
    });


var app = builder.Build();

... 以下省略 ...

MyAsyncPageFilterは、ILoggerのインスタンスをコンストラクタで受け取りたいのですが、残念ながらDIで自動で渡すことができません。

そのため、独自にLoggerFactory.Createを使って、Loggerインスタンスを生成しています。

MyAsyncPageFilter内では、

_logger.LogTrace(...);

とTraceログを出力していますので、LoggerFactory.Create時に、ログレベルを指定しています。

 config.SetMinimumLevel(LogLevel.Trace);

実行してみる

これで、MyAsyncPageFilterがグローバルで組み込まれたので、ページにアクセスがあるたびにログが出力されることになります。

テストをわかりやすくするために、appsettings.Development.json を書き換えて、フレームワーク側が出すログレベルを変更します。

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning"
    }
  }
}

それでは実行してみます。
「ASP.NET Core Web アプリ」プロジェクトを新規作成した時にできるサンプルプロジェクトに前述のコードを組み込んだ状態で実行しています。プロジェクトの名前を WebAppSample としています。

コンソールにログが出力されていることを確認できるように、デバッグでは、「IIS Express」ではなく、プロジェクト名の「WebAppSample」を選んでデバッグします。

2022-11-23 11_33_13-WebAppSample - Microsoft Visual Studio.png

以下、Homeページを開いた後に、Privacyページにアクセスした結果です。IndexページのOnGetメソッド、PrivacyページのOnGetメソッドが呼び出されているのが確認できます。

2022-11-23 11_35_22-Privacy Policy - WebAppSample.png

2022-11-23 11_34_35-E__repos_WebAppSample_WebAppSample_bin_Debug_net6.0_WebAppSample.exe.png

3
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2