Using Razor together with ASP.NET Web API

On the blog post “If Then, If Then, If Then, MVC” I found the following code example:

[HttpGet]<br><span>public</span> ActionResult List() 
{
    var list = <span>new</span>[] { <span>"John"</span>, <span>"Pete"</span>, <span>"Ben"</span> };

    <span>if</span> (Request.AcceptTypes.Contains(<span>"application/json"</span>)) {
        <span>return</span> Json(list, JsonRequestBehavior.AllowGet);
    }

    <span>if</span> (Request.IsAjaxRequest()) [
        <span>return</span> PartialView(<span>"_List"</span>, list);
    }

    <span>return</span> View(list);
}


The code is a ASP.NET MVC Controller where it reuse the same “business” code but returns JSON if the request require JSON, a partial view when the request is an AJAX request or a normal ASP.NET MVC View.

The above code may have several reasons to be changed, and also do several things, the code is not closed for modifications. To extend the code with a new way of presenting the model, the code need to be modified. So I started to think about how the above code could be rewritten so it will follow the Single Responsibility and open-close principle. I came up with the following result and with the use of ASP.NET Web API:

<span>public</span> String[] Get()
{
      <span>return</span> <span>new</span>[] { <span>"John"</span>, <span>"Pete"</span>, <span>"Ben"</span> };
}

 

It just returns the model, nothing more. The code will do one thing and it will do it well. But it will not solve the problem when it comes to return Views. If we use the ASP.NET Web Api we can get the result as JSON or XML, but not as a partial view or as a ASP.NET MVC view. Wouldn’t it be nice if we could do the following against the Get() method?

 

Accept: application/json

JSON will be returned – Already part of the Web API

 

Accept: text/html

Returns the model as HTML by using a View

 

The best thing, it’s possible!

 

By using the RazorEngine I created a custom MediaTypeFormatter (RazorFormatter, code at the end of this blog post) and associate it with the media type “text/html”. I decided to use convention before configuration to decide which Razor view should be used to render the model. To register the formatter I added the following code to Global.asax:

GlobalConfiguration.Configuration.Formatters.Add(<span>new</span> RazorFormatter());


Here is an example of a ApiController that just simply returns a model:

<span>using</span> System.Web.Http;

<span>namespace</span> WebApiRazor.Controllers
{
    <span>public</span> <span>class</span> CustomersController : ApiController
    {
        <span>// GET api/values</span>
        <span>public</span> Customer Get()
        {
            <span>return</span> <span>new</span> Customer { Name = <span>"John Doe"</span>, Country = <span>"Sweden"</span> };
        }
    }

    <span>public</span> <span>class</span> Customer
    {
        <span>public</span> <span>string</span> Name { get; set; }

        <span>public</span> <span>string</span> Country { get; set; }
    }
}

 

Because I decided to use convention before configuration I only need to add a view with the same name as the model, Customer.cshtml, here is the example of the View:

 

&lt;!DOCTYPE html&gt;
&lt;html&gt;
    
    &lt;head&gt;
        &lt;script src=<span>"http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js"</span> type=<span>"text/javascript"</span>&gt;&lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;

        &lt;div id=<span>"body"</span>&gt;
            &lt;section&gt;
                
                &lt;div&gt;
                    &lt;hgroup&gt;
                        &lt;h1&gt;Welcome <span>'@Model.Name'</span> to ASP.NET Web API Razor Formatter!&lt;/h1&gt;
                    &lt;/hgroup&gt;
                &lt;/div&gt;
                &lt;p&gt;
                    Using the same URL <span>"api/values"</span> but <span>using</span> AJAX: &lt;button&gt;Press to show content!&lt;/button&gt;
                &lt;/p&gt;
                &lt;p&gt;
                    
                &lt;/p&gt;

            &lt;/section&gt;
        &lt;/div&gt;

    &lt;/body&gt;
    
    &lt;script type=<span>"text/javascript"</span>&gt;

        $(<span>"button"</span>).click(function () {

            $.ajax({
                url: <span>'/api/values'</span>,
                type: <span>"GET"</span>,
                contentType: <span>"application/json; charset=utf-8"</span>,
                success: function(data, status, xhr)
                {
                    alert(data.Name);
                },
                error: function(xhr, status, error)
                {
                    alert(error);
                }});
            });
&lt;/script&gt;
&lt;/html&gt;

 

Now when I open up a browser and enter the following URL: http://localhost/api/customers the above View will be displayed and it will render the model the ApiController returns. If I use Ajax against the same ApiController with the content type set to “json”, the ApiController will now return the model as JSON.

Here is a part of a really early prototype of the Razor formatter (The code is far from perfect, just use it for testing). I will rewrite the code and also make it possible to specify an attribute to the returned model, so it can decide which view to be used when the media type is “text/html”, but by default the formatter will use convention:

<span>using</span> System;
<span>using</span> System.Net.Http.Formatting;

<span>namespace</span> WebApiRazor.Models
{
    <span>using</span> System.IO;
    <span>using</span> System.Net;
    <span>using</span> System.Net.Http.Headers;
    <span>using</span> System.Reflection;
    <span>using</span> System.Threading.Tasks;

    <span>using</span> RazorEngine;

    <span>public</span> <span>class</span> RazorFormatter : MediaTypeFormatter
    {
        <span>public</span> RazorFormatter()
        {
            SupportedMediaTypes.Add(<span>new</span> MediaTypeHeaderValue(<span>"text/html"</span>)); 
            SupportedMediaTypes.Add(<span>new</span> MediaTypeHeaderValue(<span>"application/xhtml+xml"</span>));
        }

        //...<br><span>public</span> <span>override</span> Task WriteToStreamAsync(
                                                Type type,
                                                <span>object</span> <span>value</span>,
                                                Stream stream,
                                                HttpContentHeaders contentHeaders,
                                                TransportContext transportContext)
        {
            var task = Task.Factory.StartNew(() =&gt;
                {
<span>                    var viewPath = // Get path to the view by the name of the type</span>

                    var template = File.ReadAllText(viewPath);

                    Razor.Compile(template, type, type.Name);
                    var razor = Razor.Run(type.Name, <span>value</span>);

                    var buf = System.Text.Encoding.Default.GetBytes(razor);

                    stream.Write(buf, 0, buf.Length);

                    stream.Flush();
                });

            <span>return</span> task;
        }
    }
}

 

Summary

By using formatters and the ASP.NET Web API we can easily just extend our code without doing any changes to our ApiControllers when we want to return a new format. This blog post just showed how we can extend the Web API to use Razor to format a returned model into HTML.

 

If you want to know when I will post more blog posts, please feel free to follow me on twitter:   @fredrikn

Read More

Smidigare manuell testning i flera browsers

En produkt/lösning jag missat som jag hörde talas om på devmobile.se var det som phonegap-folk skapat, kallat Adobe Shadow. På en android-mobil kan man dra hem en liten app som drar igång en fullscreen WebView med en proxy konfigurerad. Appen registrerar sig hos utvecklarens shadow-serverdel (en chrome extension) och kan därefter styras från utvecklaren via […]

Read More

Att underhålla en databas (del 1)

Om du utvecklar en applikation som använder sig av en SQL databas så är chansen stor, om inte oundviklig, att du måste underhålla databasschemat under utveckling såväl som både schema och data när applikationen väl är satt i produktion. Jag tänkte snabbt gå igenom de saker som jag personligen ser som mest fundamentala då det […]

Read More

Kodkväll med Scalatron

Sugen på lite socialt kodande innan semestern? Häng med på vår mjukstart av Hackathons Göteborg. Torsdagen 5/7 kör vi en liten turnering i Scalatron. Vare sig du vill komma igång med Scala, förbättra dina existerande kunskaper, skriva logiskt fulländade bottar eller bara inspireras under en social kodkväll så är det här något för dig. Scalatron […]

Read More

ASP.NET Web API Exception Handling

When I talk about exceptions in my product team I often talk about two kind of exceptions, business and critical exceptions. Business exceptions are exceptions thrown based on “business rules”, for example if you aren’t allowed to do a purchase. Business exceptions in most case aren’t important to log into a log file, they can directly be shown to the user. An example of a business exception could be “DeniedToPurchaseException”, or some validation exceptions such as “FirstNameIsMissingException” etc.

Critical Exceptions are all other kind of exceptions such as the SQL server is down etc. Those kind of exception message need to be logged and should not reach the user, because they can contain information that can be harmful if it reach out to wrong kind of users.

I often distinguish business exceptions from critical exceptions by creating a base class called BusinessException, then in my error handling code I catch on the type BusinessException and all other exceptions will be handled as critical exceptions.

This blog post will be about different ways to handle exceptions and how Business and Critical Exceptions could be handled.

Web API and Exceptions the basics

When an exception is thrown in a ApiController a response message will be returned with a status code set to 500 and a response formatted by the formatters based on the “Accept” or “Content-Type” HTTP header, for example JSON or XML. Here is an example:

 

        <span>public</span> IEnumerable&lt;<span>string</span>&gt; Get()
        {
            <span>throw</span> <span>new</span> ApplicationException(<span>"Error!!!!!"</span>);

            <span>return</span> <span>new</span> <span>string</span>[] { <span>"value1"</span>, <span>"value2"</span> };
        }

The response message will be:

HTTP/1.1 500 Internal Server Error
Content-Length: 860
Content-Type: application/json; charset=utf-8

{ <span>"ExceptionType"</span>:<span>"System.ApplicationException"</span>,<span>"Message"</span>:<span>"Error!!!!!"</span>,<span>"StackTrace"</span>:<span>"   at ..."</span>}

 

The stack trace will be returned to the client, this is because of making it easier to debug. Be careful so you don’t leak out some sensitive information to the client. So as long as you are developing your API, this is not harmful. In a production environment it can be better to log exceptions and return a user friendly exception instead of the original exception.

There is a specific exception shipped with ASP.NET Web API that will not use the formatters based on the “Accept” or “Content-Type” HTTP header, it is the exception is the HttpResponseException class.

Here is an example where the HttpReponseExcetpion is used:

        <span>// GET api/values</span>
        [ExceptionHandling]
        <span>public</span> IEnumerable&lt;<span>string</span>&gt; Get()
        {
            <span>throw</span> <span>new</span> HttpResponseException(<span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError));

            <span>return</span> <span>new</span> <span>string</span>[] { <span>"value1"</span>, <span>"value2"</span> };
        }


The response will not contain any content, only header information and the status code based on the HttpStatusCode passed as an argument to the HttpResponseMessage. Because the HttpResponsException takes a HttpResponseMessage as an argument, we can give the response a content:

        <span>public</span> IEnumerable&lt;<span>string</span>&gt; Get()
        {
            <span>throw</span> <span>new</span> HttpResponseException(<span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
                                                {
                                                    Content = <span>new</span> StringContent(<span>"My Error Message"</span>),
                                                    ReasonPhrase = <span>"Critical Exception"</span>
                                                });

            <span>return</span> <span>new</span> <span>string</span>[] { <span>"value1"</span>, <span>"value2"</span> };
        }

 

The code above will have the following response:

 

HTTP/1.1 500 Critical Exception
Content-Length: 5
Content-Type: text/plain; charset=utf-8

My Error Message

The Content property of the HttpResponseMessage doesn’t need to be just plain text, it can also be other formats, for example JSON, XML etc.

By using the HttpResponseException we can for example catch an exception and throw a user friendly exception instead:

        <span>public</span> IEnumerable&lt;<span>string</span>&gt; Get()
        {
            <span>try</span>
            {
                DoSomething();

                <span>return</span> <span>new</span> <span>string</span>[] { <span>"value1"</span>, <span>"value2"</span> };

            }
            <span>catch</span> (Exception e)
            {
                <span>throw</span> <span>new</span> HttpResponseException(<span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
                                                {
                                                    Content = <span>new</span> StringContent(<span>"An error occurred, please try again or contact the administrator."</span>),
                                                    ReasonPhrase = <span>"Critical Exception"</span>
                                                });
            }
        }

 

Adding a try catch to every ApiController methods will only end in duplication of code, by using a custom ExceptionFilterAttribute or our own custom ApiController base class we can reduce code duplicationof code and also have a more general exception handler for our ApiControllers . By creating a custom ApiController’s and override the ExecuteAsync method, we can add a try catch around the base.ExecuteAsync method, but I prefer to skip the creation of a own custom ApiController, better to use a solution that require few files to be modified.

The ExceptionFilterAttribute has a OnException method that we can override and add our exception handling. Here is an example:

    <span>using</span> System;
    <span>using</span> System.Diagnostics;
    <span>using</span> System.Net;
    <span>using</span> System.Net.Http;
    <span>using</span> System.Web.Http;
    <span>using</span> System.Web.Http.Filters;

    <span>public</span> <span>class</span> ExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        <span>public</span> <span>override</span> <span>void</span> OnException(HttpActionExecutedContext context)
        {
            <span>if</span> (context.Exception <span>is</span> BusinessException)
            {
                <span>throw</span> <span>new</span> HttpResponseException(<span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    Content = <span>new</span> StringContent(context.Exception.Message),
                    ReasonPhrase = <span>"Exception"</span>
                });

            }<br>
            //Log Critical errors<br>            Debug.WriteLine(context.Exception);

            <span>throw</span> <span>new</span> HttpResponseException(<span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = <span>new</span> StringContent(<span>"An error occurred, please try again or contact the administrator."</span>),
                ReasonPhrase = <span>"Critical Exception"</span>
            });
        }
    }

 

Note: Something to have in mind is that the ExceptionFilterAttribute will be ignored if the ApiController action method throws a HttpResponseException.

The code above will always make sure a HttpResponseExceptions will be returned, it will also make sure the critical exceptions will show a more user friendly message. The OnException method can also be used to log exceptions.

By using a ExceptionFilterAttribute the Get() method in the previous example can now look like this:

        <span>public</span> IEnumerable&lt;<span>string</span>&gt; Get()
        {
                DoSomething();

                <span>return</span> <span>new</span> <span>string</span>[] { <span>"value1"</span>, <span>"value2"</span> };
        }


To use the an ExceptionFilterAttribute, we can for example add the ExceptionFilterAttribute to our ApiControllers methods or to the ApiController class definition, or register it globally for all ApiControllers. You can read more about is here.

Note: If something goes wrong in the ExceptionFilterAttribute and an exception is thrown that is not of type HttpResponseException, a formatted exception will be thrown with stack trace etc to the client.

How about using a custom IHttpActionInvoker?

We can create our own IHTTPActionInvoker and add Exception handling to the invoker. The IHttpActionInvoker will be used to invoke the ApiController’s ExecuteAsync method. Here is an example where the default IHttpActionInvoker, ApiControllerActionInvoker, is used to add exception handling:

    <span>public</span> <span>class</span> MyApiControllerActionInvoker : ApiControllerActionInvoker
    {
        <span>public</span> <span>override</span> Task&lt;HttpResponseMessage&gt; InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
            var result = <span>base</span>.InvokeActionAsync(actionContext, cancellationToken);

            <span>if</span> (result.Exception != <span>null</span> &amp;&amp; result.Exception.GetBaseException() != <span>null</span>)
            {
                var baseException = result.Exception.GetBaseException();

                <span>if</span> (baseException <span>is</span> BusinessException)
                {
                    <span>return</span> Task.Run&lt;HttpResponseMessage&gt;(() =&gt; <span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
                                                                {
                                                                    Content = <span>new</span> StringContent(baseException.Message),
                                                                    ReasonPhrase = <span>"Error"</span>

                                                                });
                }
                <span>else</span>
                {
                    <span>//Log critical error</span>
                    Debug.WriteLine(baseException);

                    <span>return</span> Task.Run&lt;HttpResponseMessage&gt;(() =&gt; <span>new</span> HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = <span>new</span> StringContent(baseException.Message),
                        ReasonPhrase = <span>"Critical Error"</span>
                    });
                }
            }

            <span>return</span> result;
        }
    }

You can register the IHttpActionInvoker with your own IoC to resolve the MyApiContollerActionInvoker, or add it in the Global.asax:

GlobalConfiguration.Configuration.Services.Remove(<span>typeof</span>(IHttpActionInvoker), GlobalConfiguration.Configuration.Services.GetActionInvoker());

GlobalConfiguration.Configuration.Services.Add(<span>typeof</span>(IHttpActionInvoker), <span>new</span> MyApiControllerActionInvoker());

 

How about using a Message Handler for Exception Handling?

By creating a custom Message Handler, we can handle error after the ApiController and the ExceptionFilterAttribute is invoked and in that way create a global exception handler, BUT, the only thing we can take a look at is the HttpResponseMessage, we can’t add a try catch around the Message Handler’s SendAsync method. The last Message Handler that will be used in the Wep API pipe-line is the HttpControllerDispatcher and this Message Handler is added to the HttpServer in an early stage. The HttpControllerDispatcher will use the IHttpActionInvoker to invoke the ApiController method. The HttpControllerDipatcher has a try catch that will turn ALL exceptions into a HttpResponseMessage, so that is the reason why a try catch around the SendAsync in a custom Message Handler want help us. If we create our own Host for the Wep API we could create our own custom HttpControllerDispatcher and add or exception handler to that class, but that would be little tricky but is possible.

We can in a Message Handler take a look at the HttpResponseMessage’s IsSuccessStatusCode property to see if the request has failed and if we throw the HttpResponseException in our ApiControllers, we could use the HttpResponseException and give it a Reason Phrase and use that to identify business exceptions or critical exceptions.

I wouldn’t add an exception handler into a Message Handler, instead I should use the ExceptionFilterAttribute and register it globally for all ApiControllers. BUT, now to another interesting issue. What will happen if we have a Message Handler that throws an exception?  Those exceptions will not be catch and handled by the ExceptionFilterAttribute.

I found a  bug in my previews blog post about “Log message Request and Response in ASP.NET WebAPI” in the MessageHandler I use to log incoming and outgoing messages. Here is the code from my blog before I fixed the bug:

 

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

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

            await IncommingMessageAsync(corrId, requestInfo, requestMessage);

            var response = await <span>base</span>.SendAsync(request, cancellationToken);

            var responseMessage = await response.Content.ReadAsByteArrayAsync();

            await OutgoingMessageAsync(corrId, requestInfo, responseMessage);

            <span>return</span> response;
        }

        <span>protected</span> <span>abstract</span> Task IncommingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
        <span>protected</span> <span>abstract</span> Task OutgoingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
    }

 

If a ApiController throws a HttpResponseException, the Content property of the HttpResponseMessage from the SendAsync will be NULL. So a null reference exception is thrown within the MessageHandler. The yellow screen of death will be returned to the client, and the content is HTML and the Http status code is 500. The bug in the MessageHandler was solved by adding a check against the HttpResponseMessage’s IsSuccessStatusCode property:

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

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

            await IncommingMessageAsync(corrId, requestInfo, requestMessage);

            var response = await <span>base</span>.SendAsync(request, cancellationToken);

            <span>byte</span>[] responseMessage;

            <span>if</span> (response.IsSuccessStatusCode)
                responseMessage = await response.Content.ReadAsByteArrayAsync();
            <span>else</span>
                responseMessage = Encoding.UTF8.GetBytes(response.ReasonPhrase);

            await OutgoingMessageAsync(corrId, requestInfo, responseMessage);

            <span>return</span> response;
        }

        <span>protected</span> <span>abstract</span> Task IncommingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
        <span>protected</span> <span>abstract</span> Task OutgoingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
    }<br>


If we don’t handle the exceptions that can occur in a custom Message Handler, we can have a hard time to find the problem causing the exception. The savior in this case is the Global.asax’s Application_Error:

        <span>protected</span> <span>void</span> Application_Error()
        {
            var exception = Server.GetLastError();

            Debug.WriteLine(exception);
        }


I would recommend you to add the Application_Error to the Global.asax and log all exceptions to make sure all kind of exception is handled.


Summary

There are different ways we could add Exception Handling to the Wep API, we can use a custom ApiController, ExceptionFilterAttribute, IHttpActionInvoker or Message Handler. The ExceptionFilterAttribute would be a good place to add a global exception handling, require very few modification, just register it globally for all ApiControllers, even the IHttpActionInvoker can be used to minimize the modifications of files. Adding the Application_Error to the global.asax is a good way to catch all unhandled exception that can occur, for example exception thrown in a Message Handler.

 

If you want to know when I have posted a blog post, you can follow me on twitter @fredrikn

Read More

Log message Request and Response in ASP.NET WebAPI

By logging both incoming and outgoing messages for services can be useful in many scenarios, such as debugging, tracing, inspection and helping customers with request problems etc.  I have a customer that need to have both incoming and outgoing messages to be logged. They use the information to see strange behaviors and also to help customers when they call in  for help (They can by looking in the log see if the customers sends in data in a wrong or strange way).

Concerns

Most loggings in applications are cross-cutting concerns and should not be  a core concern for developers. Logging messages like this:

        <span>// GET api/values/5</span>
        <span>public</span> <span>string</span> Get(<span>int</span> id)
        {
            <span>//Cross-cutting concerns</span>
            Log(<span>string</span>.Format(<span>"Request: GET api/values/{0}"</span>, id));

            <span>//Core-concern</span>
            var response = DoSomething();

            <span>//Cross-cutting concerns</span>
            Log(<span>string</span>.Format(<span>"Reponse: GET api/values/{0}\r\n{1}"</span>, id, response));

            <span>return</span> response;
        }


will only result in duplication of code, and unnecessarily concerns for the developers to be aware of, if they miss adding the logging code, no logging will take place. Developers should focus on the core-concern, not the cross-cutting concerns. By just focus on the core-concern the above code will look like this:

        <span>// GET api/values/5</span>
        <span>public</span> <span>string</span> Get(<span>int</span> id)
        {
            <span>return</span> DoSomething();
        }


The logging should then be placed somewhere else so the developers doesn’t need to focus care about the cross-concern.

Using Message Handler for logging

There are different ways we could place the cross-cutting concern of logging message when using WebAPI. We can for example create a custom ApiController and override the ApiController’s ExecutingAsync method, or add a ActionFilter, or use a Message Handler. The disadvantage with custom ApiController is that we need to make sure we inherit from it, the disadvantage of ActionFilter, is that we need to add the filter to the controllers, both will modify our ApiControllers. By using a Message Handler we don’t need to do any changes to our ApiControllers. So the best suitable place to add our logging would be in a custom Message Handler. A Message Handler will be used before the HttpControllerDispatcher (The part in the WepAPI pipe-line that make sure the right controller is used and called etc).

Note: You can read more about message handlers here, it will give you a good understanding of the WebApi pipe-line.

To create a Message Handle we can inherit from the DelegatingHandler class and override the SendAsync method:

    <span>public</span> <span>class</span> MessageHandler : DelegatingHandler
    {
        <span>protected</span> <span>override</span> async Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
           <span>return</span> <span>base</span>.SendAsync(request, cancellationToken);
        }
    }

If we skip the call to the base.SendAsync our ApiController’s methods will never be invoked, nor other Message Handlers. Everything placed before base.SendAsync will be called before the HttpControllerDispatcher (before WebAPI will take a look at the request which controller and method it should be invoke), everything after the base.SendAsync, will be executed after our ApiController method has returned a response. So a message handle will be a perfect place to add cross-cutting concerns such as logging.

To get the content of our response within a Message Handler we can use the request argument of the SendAsync method. The request argument is of type HttpRequestMessage and has a Content property (Content is of type HttpContent. The HttpContent has several method that can be used to read the incoming message, such as ReadAsStreamAsync, ReadAsByteArrayAsync and ReadAsStringAsync etc.

Something to be aware of is what will happen when we read from the HttpContent. When we read from the HttpContent, we read from a stream, once we read from it, we can’t be read from it again. So if we read from the Stream before the base.SendAsync, the next coming Message Handlers and the HttpControllerDispatcher can’t read from the Stream because it’s already read, so our ApiControllers methods will never be invoked etc. The only way to make sure we can do repeatable reads from the HttpContent is to copy the content into a buffer, and then read from that buffer. This can be done by using the HttpContent’s LoadIntoBufferAsync method. If we make a call to the LoadIntoBufferAsync method before the base.SendAsync, the incoming stream will be read in to a byte array, and then other HttpContent read operations will read from that buffer if it’s exists instead directly form the stream. There is one method on the HttpContent that will internally make a call to the  LoadIntoBufferAsync for us, and that is the ReadAsByteArrayAsync. This is the method we will use to read from the incoming and outgoing message.

    <span>public</span> <span>abstract</span> <span>class</span> MessageHandler : DelegatingHandler
    {
        <span>protected</span> <span>override</span> async Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var requestMessage = await request.Content.ReadAsByteArrayAsync();

            var response = await <span>base</span>.SendAsync(request, cancellationToken);

            var responseMessage = await response.Content.ReadAsByteArrayAsync();

            <span>return</span> response;
        }
    }


The above code will read the content of the incoming message and then call the SendAsync and after that read from the content of the response message.

The following code will add more logic such as creating a correlation id to combine the request with the response, and create a log entry etc:

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

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

            await IncommingMessageAsync(corrId, requestInfo, requestMessage);

            var response = await <span>base</span>.SendAsync(request, cancellationToken);

            <span>byte</span>[] responseMessage;

            <span>if</span> (response.IsSuccessStatusCode)
                responseMessage = await response.Content.ReadAsByteArrayAsync();
            <span>else</span>
                responseMessage = Encoding.UTF8.GetBytes(response.ReasonPhrase);

            await OutgoingMessageAsync(corrId, requestInfo, responseMessage);

            <span>return</span> response;
        }

        <span>protected</span> <span>abstract</span> Task IncommingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
        <span>protected</span> <span>abstract</span> Task OutgoingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message);
    }

    <span>public</span> <span>class</span> MessageLoggingHandler : MessageHandler
    {
        <span>protected</span> <span>override</span> async Task IncommingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message)
        {
            await Task.Run(() =&gt;
                Debug.WriteLine(<span>string</span>.Format(<span>"{0} - Request: {1}\r\n{2}"</span>, correlationId, requestInfo, Encoding.UTF8.GetString(message))));
        }

        <span>protected</span> <span>override</span> async Task OutgoingMessageAsync(<span>string</span> correlationId, <span>string</span> requestInfo, <span>byte</span>[] message)
        {
            await Task.Run(() =&gt;
                Debug.WriteLine(<span>string</span>.Format(<span>"{0} - Response: {1}\r\n{2}"</span>, correlationId, requestInfo, Encoding.UTF8.GetString(message))));
        }
    }

The code above will show the following in the Visual Studio output window when the “api/values” service (One standard controller added by the default WepAPI template) is requested with a Get http method :

6347483479959544375 - Request: GET http:<span>//localhost:3208/api/values</span>

6347483479959544375 - Response: GET http:<span>//localhost:3208/api/values</span>
[<span>"value1"</span>,<span>"value2"</span>]

Register a Message Handler

To register a Message handler we can use the Add method of the GlobalConfiguration.Configration.MessageHandlers in for example Global.asax:

    <span>public</span> <span>class</span> WebApiApplication : System.Web.HttpApplication
    {
        <span>protected</span> <span>void</span> Application_Start()
        {
           <strong> GlobalConfiguration.Configuration.MessageHandlers.Add(<span>new</span> MessageLoggingHandler());</strong>
            

            ...

        }
    }

Summary

By using a Message Handler we can easily remove cross-cutting concerns like logging from our controllers.

You can also find the source code used in this blog post on ForkCan.com, feel free to make a fork or add comments, such as making the code better etc.


Feel free to follow me on twitter @fredrikn if you want to know when I will write other blog posts etc.

Read More

En vecka kvar till dev:mobile

Med en vecka kvar till dev:mobile ser det ut som om det kommer att bli en riktigt bra konferens. Vad sägs om 25 sessioner (Microsoft, IBM, Nokia, Adobe, med flera), keynote av Erwan Paccard om “Top 11 Trends for Enterprise Mobile”. Konferensen är fullsatt men det går fortfarande att registrera sig på reservlistan Vi ses den […]

Read More