Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to auto log every request in .NET Core WebAPI?

I'd like to have every request logged automatically. In previous .Net Framwork WebAPI project, I used to register a delegateHandler to do so.

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;
            });
    }
}

an example of the log content:

------------------------------------------------------
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"}
------------------------------------------------------

But in .NET Core WebAPI project, there is no WebApiConfig , or the register function at Global.asax GlobalConfiguration.Configure(WebApiConfig.Register);

So is there any way to achieve that in .NET Core WebAPI?

like image 831
wtf512 Avatar asked Aug 03 '17 08:08

wtf512


3 Answers

ActionFilter will work until you need to log only requests processed by MVC middleware (as controller actions).

If you need logging for all incoming requests, then you need to use a middleware approach.

Good visual explanation: enter image description here

Note that middleware order is important, and if your logging should be done at the start of pipeline execution, your middleware should be one of the first one.

Simple example from 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.
        });
like image 92
Set Avatar answered Nov 19 '22 20:11

Set


You can create your own filter attribute...

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);
  }
}

... and you would register it with GlobalFilters, but since you said you're using .NET Core, this is how you can try proceeding...

From learn.microsoft.com:

You can register a filter globally (for all controllers and actions) by adding it to the MvcOptions.Filters collection in the ConfigureServices method in the Startup class:

Let us know if it worked.

P.S. Here's a whole tutorial on intercepting requests with WebAPI, in case someone needs more details.

like image 35
Eedoh Avatar answered Nov 19 '22 19:11

Eedoh


For someone that wants a quick and (very) dirty solution for debugging purposes (that works on .Net Core 3), here's an expansion of this answer that's all you need...

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;
    }
});
like image 12
ihake Avatar answered Nov 19 '22 20:11

ihake