Search code examples
c#postasp.net-web-apicontrollerhttpcontext

HttpContext is null after adding MessageHandler


I am developing a WebAPI and have been receiving my POST data like this:

[HttpPost]
        public Int16 Foo()
        {
            var input = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEnd();
            Model_Deserialized model = JsonConvert.DeserializeObject<Model_Deserialized>(input);
            ...
        }

Recently I felt the need to log all the requests there were being sent over. I am trying to use the method suggested at http://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi but after following those steps, my input variable started being an empty string.

This is how my Message Handler looks like

public abstract class MessageHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var corrId = string.Format("{0}{1}", DateTime.Now.Ticks, Thread.CurrentThread.ManagedThreadId);
            var requestInfo = string.Format("{0} {1}", request.Method, request.RequestUri);

            var requestMessage = await request.Content.ReadAsByteArrayAsync();

            String ip;

            if (request.Properties.ContainsKey("MS_HttpContext"))
            {
                var ctx = request.Properties["MS_HttpContext"] as HttpContextWrapper;
                if (ctx != null)
                {
                    ip = ctx.Request.UserHostAddress;
                }
            }

            else
            {
                 ip = "error";
            }

            await IncommingMessageAsync(corrId, requestInfo, requestMessage, ip);

            var response = await base.SendAsync(request, cancellationToken);

            return response;
        }


        protected abstract Task IncommingMessageAsync(string correlationId, string requestInfo, byte[] message, String ip);
    }

and this is my MessageLoggingHandler

public class MessageLoggingHandler : MessageHandler
    {
        protected override async Task IncommingMessageAsync(string correlationId, string requestInfo, byte[] message, String ip)
        {
            await Task.Run(() =>
                WriteToFile(ip + "{" + correlationId + "} - Request: {" + requestInfo + "}\r\n{" + Encoding.UTF8.GetString(message) + "}"));
        }


        private void WriteToFile(string text)
        {
            string path = "C:\\Logs\\ServiceLog" + DateTime.Now.Year + "-" + DateTime.Now.Month + "-" + DateTime.Now.Day + ".txt";
            using (StreamWriter writer = new StreamWriter(path, true))
            {
                writer.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt") + "--" + text);
                writer.Close();
            }
        }
    }

I also added this to my Global.asax

GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageLoggingHandler());

In my web.config I already tried adding

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
<compilation debug="true" targetFramework="4.5">

Is there anyway to stick to this method instead of creating a logging routine and call it from every function?


Solution

  • Just to be clear HttpContext cannot be null - it is static. So is HttpContext.Current null? OR my guess is that HttpContext.Current.Request.InputStream is null. Web api automatically reads the stream and disposes it and deserializes the post body to your action input. So you should code your Web Api action to something like the following:

    [HttpPost]
    public Int16 Foo(Model_Deserialized model)
    {
    
        ...
    }