web-dev-qa-db-ja.com

.NET Core WebAPIですべてのリクエストを自動記録する方法は?

すべてのリクエストが自動的に記録されるようにしたいと思います。以前の.Net Framwork WebAPIプロジェクトでは、これを行うためにdelegateHandlerを登録していました。

WebApiConfig.cs

_public static void Register(HttpConfiguration config)
{
    config.MessageHandlers.Add(new AutoLogDelegateHandler());
}
_

AutoLogDelegateHandler.cs

_public class AutoLogDelegateHandler : DelegatingHandler
{

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var requestBody = request.Content.ReadAsStringAsync().Result;

        return await base.SendAsync(request, cancellationToken)
            .ContinueWith(task =>
            {
                HttpResponseMessage response = task.Result;

                //Log use log4net
                _LogHandle(request, requestBody, response);

                return response;
            });
    }
}
_

ログの内容の例:

_------------------------------------------------------
2017-08-02 19:34:58,840
uri: /emp/register
body: {
    "timeStamp": 1481013427,
    "id": "0322654451",
    "type": "t3",
    "remark": "system auto reg"
}
response: {"msg":"c556f652fc52f94af081a130dc627433","success":"true"}
------------------------------------------------------
_

ただし、.NET Core WebAPIプロジェクトでは、WebApiConfigや、Global.asaxの登録関数GlobalConfiguration.Configure(WebApiConfig.Register);はありません。

それで、.NET Core WebAPIでそれを達成する方法はありますか?

11
wtf512

独自のフィルター属性を作成できます...

public class InterceptionAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(HttpActionContext actionContext)
  {
    var x = "This is my custom line of code I need executed before any of the controller actions, for example log stuff";
    base.OnActionExecuting(actionContext);
  }
}

...そして、それをGlobalFiltersに登録しますが、.NET Coreを使用していると言ったので、これが続行を試す方法です...

docs.Microsoft.com から:

スタートアップクラスのConfigureServicesメソッドのMvcOptions.Filtersコレクションにフィルターを追加することにより、フィルターをグローバルに(すべてのコントローラーとアクションに対して)登録できます。

うまくいったかどうか教えてください。

追伸誰かが詳細を必要とする場合のために、 WebAPIを使用したリクエストのインターセプトに関するチュートリアル全体 を以下に示します。

8
Eedoh

ActionFilterは、MVCミドルウェアによって処理されたonlyリクエストを(コントローラーアクションとして)ログに記録する必要があるまで機能します。

すべての着信要求のロギングが必要な場合は、ミドルウェアアプローチを使用する必要があります。

良いビジュアル 説明enter image description here

ミドルウェアの順序が重要であり、ロギングをパイプライン実行の開始時に行う必要がある場合、ミドルウェアは最初のミドルウェアの1つでなければなりません。

docs の簡単な例:

public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do loging
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });
23
Set

デモ:

AutologArribute.cs(新しいファイル)

/// <summary>
/// <see cref="https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters#Dependency injection"/>
/// </summary>
public class AutoLogAttribute : TypeFilterAttribute
    {
        public AutoLogAttribute() : base(typeof(AutoLogActionFilterImpl))
        {

        }

        private class AutoLogActionFilterImpl : IActionFilter
        {
            private readonly ILogger _logger;
            public AutoLogActionFilterImpl(ILoggerFactory loggerFactory)
            {
                _logger = loggerFactory.CreateLogger<AutoLogAttribute>();
            }

            public void OnActionExecuting(ActionExecutingContext context)
            {
                // perform some business logic work
            }

            public void OnActionExecuted(ActionExecutedContext context)
            {
                //TODO: log body content and response as well
                _logger.LogDebug($"path: {context.HttpContext.Request.Path}"); 
            }
        }
    }

StartUp.cs

public void ConfigureServices(IServiceCollection services)
{
    //....

    // https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters#filter-scopes-and-order-of-execution
    services.AddMvc(opts=> {
        opts.Filters.Add(new AutoLogAttribute());
    });

    //....
}
3
wtf512

デバッグ目的で(.Net Core 3で動作する)迅速で(非常に)ダーティーなソリューションを必要とする人のために、ここに この答え の拡張があります...

    app.Use(async (context, next) =>
        {
            var initialBody = context.Request.Body;

            using (var bodyReader = new StreamReader(context.Request.Body))
            {
                string body = await bodyReader.ReadToEndAsync();
                Console.WriteLine(body);
                context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(body));
                await next.Invoke();
                context.Request.Body = initialBody;
            }
        });
0
ihake