krisdyson krisdyson - 2 months ago 28
ASP.NET (C#) Question

Web API audit logging

I need to audit log calls to my Web API, ideally I'd like to use an Attribute, something like:

[HttpPost, Auditing]
public dynamic MyAPICall()


The Attribute should be able to intercept the API call before and after execution in order to log the parameters and also, how long the API call took to run.

With MVC I could create an ActionFilterAttribute derivative and override OnActionExecuted and OnActionExecuting.

Is the equivalent possible in the Web API world?

Answer

I would use a message handler rather than attributes.

public class LoggingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        LogRequest(request);

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

            LogResponse(response);

            return response;
        });
    }

    private void LogRequest(HttpRequestMessage request)
    {
        (request.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
        {
            Logger.Info("{4:yyyy-MM-dd HH:mm:ss} {5} {0} request [{1}]{2} - {3}", request.GetCorrelationId(), request.Method, request.RequestUri, x.Result, DateTime.Now, Username(request));
        });
    }

    private void LogResponse(HttpResponseMessage response)
    {
        var request = response.RequestMessage;
        (response.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
        {
            Logger.Info("{3:yyyy-MM-dd HH:mm:ss} {4} {0} response [{1}] - {2}", request.GetCorrelationId(), response.StatusCode, x.Result, DateTime.Now, Username(request));
        });
    }

    private string Username(HttpRequestMessage request)
    {
        var values = new List<string>().AsEnumerable();
        if (request.Headers.TryGetValues("my-custom-header-for-current-user", out values) == false) return "<anonymous>";

        return values.First(); 
    }
}
Comments