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

I want every request to be logged automatically. In a previous .NET Framework WebAPI project, I used to register a delegateHandler for this.

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

      

example of 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 there is no WebAPI in the .NET Core project WebApiConfig

, or the register function in Global.asaxGlobalConfiguration.Configure(WebApiConfig.Register);

So, is there a way to achieve this in .NET Core WebAPI?

+8


source to share


4 answers


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 were using .NET Core, you can try to continue ...

From docs.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.

Postscript Here's a whole tutorial on intercepting WebAPI requests , in case anyone needs more details.

+8


source


ActionFilter

will work as long as you don't need to log requests only processed by the MVC middleware (as controller actions).

If you need to log all incoming requests, you need to use a middleware approach.

Nice visual explanation : enter image description here



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

Simple example from the 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.
        });

      

+18


source


Demo:

AutologArribute.cs (new file)

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

    //....
}

      

+1


source


For someone who wants a quick and (very) messy solution for debugging purposes (which works on .Net Core 3), here's an extension of that 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;
            }
        });

      

0


source







All Articles