You are on page 1of 10

7

Error Handling

In this chapter, we will cover:


 Using HTTPResponse Exception
 Creating Filter Exception
 Registering Filter Exception
 Creating HTTP Error
 Global Error handling in Web API2

Using HTTPResponse Exception

To get error or exception is a common term for every developer. I think it is good to have exception
because exception will force you to learn the things deeply. Handling error is very important for every
developer. To manage exception in web api is quite easy. In web api most exceptions are converted into
HTTP Response with a status code 500, Internal Server Error.
But HTTPResponse Exception is quite special. It returns the status code that is specified in the exception
constructor.
It is an exception type defined for WebAPI that serves two purposes:

 It allows you to return a specific HTTP response from actions with return types that aren’t
HttpResponseMessage.
 It allows you to short-circuit the WebAPI pipeline pretty much anywhere and return a response
immediately.

How to do it...
Let's look into our model class “Book” that we have created in the first chapter.

using System;
Using System.Collections.Generic;
Using System.ComponentModel.DataAnnotations;
Using System.Linq;
Using System.Web;

namespace BooksWebApi.Models
{
public class Book
{
[Key]
publicint Id { get; set; }

[Required]
publicstring Title { get; set; }

[Required]
publicstring Author { get; set; }
publicstring Category { get; set; }
publicdouble Price { get; set; }
}
}

Now we can use following HTTPResponseException message for the following method that returns 404,
Not Found, if the id parameter is not valid.

public Book GetBook(int id)


{
Book _book = BooksRepository.GetBooks(id);
if (_book == null)
throw new HttpResponseException(HttpStatusCode.NotFound);

return _book;
}

But what if we want to show the error details more precisely to the user.Asp.net Web Api provide some
cool feature to do this. It allows us to provide messages by using the HTTPResponseMessage class and
pass it to the HTTPResponseException class. HTTPResponseMessage represent a returning response
message having following having following important properties:

 StatusCode
 ReasonPhrase
 Content

public Book Get (int id)


{
Book _book = BooksRepository.GetBooks(id);
if (_book == null)
{
HttpResponseMessage responseMessage = new HttpResponseMessage();
responseMessage.StatusCode = HttpStatusCode.NotFound;
responseMessage.ReasonPhrase = "Book not found";
responseMessage.Content = new StringContent("No Book exists against
provided book id");

throw new HttpResponseException(responseMessage);


}
return _book;
}

For more control over the response, we can also construct the entire response message and include it
with theHttpResponseException:

public GetBooks(int id)


{
Book item = BooksRepository.GetBooks (id);
if (item == null)
{
var resp = new HttpResponseMessage (HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("No product with ID = {0}",
id)),
ReasonPhrase = "Product ID Not Found"
}
throw new HttpResponseException (resp);
}
return item;
}

How it works …
Technically, HttpResponseException can be used for any kind of HTTP response, but it’s especially useful
in error cases specially When we want to return an error if our action returns a different type instead of
HttpResponseMessage. The HttpResponseException type is a special case. This exception returns any
HTTP status code that we typically specify in the exception constructor.

Exception Filter

Filter Exception is used to customize how asp.net web api handles exception. From the previous part of
this chapter we saw that HttpResponseException throws exception with a meaningful HTTP status code
so that users can easily recognise but rather than those exceptions there are some other exception
which are unhandled and return common error: Internal Server Error. To handle these kind of situations
we can use Exception Filter. By using filter, we can handle exceptions in a centralized manner. A Filter
Exception executed when a method from controller throws an exception that is not an
HttpResponseException type exception.

How to do it...

We can implement Exception Filter in our web api application by following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Filters;

namespace BooksApiSelfHosting
{
public class BookExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext _ctx)
{
var exceptionType = _ctx.Exception.GetType();
if (exceptionType == typeof (UnhandledExceptionEventArgs))
{
_ctx.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
else
{
_ctx.Response = new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
}
}

** Rather than this you can add more condition based on your need.

How it works
Filter Exception is a class which implement IExceptionFilter interface. To handle such unhandled
exception, we have to create a class that should inherit from ExceptionFilterAttribute class and
override the OnException method. By using OnException method we can generate various types of
HTTP status code according to various condition.

Registering Filter Exception

Registering Filter Exception


We can register Filter Exception at different level of our application and a very easy manner. such as :
 Controller Action level
 Controller level
 Global level

How to do it...
For example, we can use our BookExceptionFilter at controller action level by using
BookExceptionFilter as an attribute as follows:

[BookExceptionFilter]
public Book GetBook(int id)
{
Book _book = BooksRepository.GetBooks(id);
if (_book == null)
throw new HttpResponseException(HttpStatusCode.NotFound);

return _book;
}

we can also use our BookExceptionFilter at controller level by using BookExceptionFilter as an


attribute as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using BooksApiSelfHosting.Model;

namespace BooksApiSelfHosting.Controller
{
[BookExceptionFilter]
public class BooksController : ApiController
{
}
}

If we want to use our ExceptionFilter to all controller of our application than we can use it globally in a
very simple manner:

1. Just create an instance of our ExceptionFilter.


2. Add to filter collections in global configuration as following:

BooksApiSelfHosting.BookExceptionFilter _bookExceptionFilter = new BookExceptionFilter();


GlobalConfiguration.Configuration.filters(_bookExceptionFilter);

How it works…
Creating HTTP Error
What if we want to return error information in response body? Simply we can do this by using the object
of HTTP Error. There is a method defined in System.Net.Http.HttpRequestMessageExtensions class
named CreateErrorResponse method. CreateErrorResponse creates an HttpError instance and then
creates an HttpErrorResponseMessage that contains the HttpError. Effectively it’s just a
Dictionary<string, object> that provides some helpers for creating errors that contains Error Messages,
exceptions and invalid model states. HttpErrors defines the following public constructors :

1: public HttpError();
2: public HttpError(string message);
3: public HttpError(Exception exception, bool includeErrorDetail);
4: public HttpError(ModelStateDictionary modelState, bool includeErrorDetail);

How to do it...
Following code snippet shows you how to create an HTTP Error:

using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using BooksApiSelfHosting.Model;

public HttpResponseMessage GetBook(int id)


{
Book book = BooksRepository.GetBooks(id);
if (book == null)
{
var message = string.Format("The book with Id ={0} not Found", id);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.OK,"Here your book");
}
}

We can also use HttpResponseException to return an HttpError. This will return a strongly typed model if
the method get any value and return an HttpError if any error occurred. We can do this by the following
code:
public Book GetBook(int id)
{
Book item = BooksRepository.GetBooks(id);
if (item == null)
{
var message = string.Format("Book with id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
}
else
{
return item;
}
}

How it works …

From the above code snippet if the method gets books according to Id than it returns book in the Http
Response. But if the requested book is not found than the Http response contains an HttpError in the
request body. The response might look like following:
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 26 Nov 2015 23:27:18 GMT
Content-Length: 51

{
"Message": "Book with id = 12 not found"
}
Here Http Error was serialized to JSON. This is a kind of advantage of HttpError that it goes through
same serialization process like any other strongly typed models.

Global Error handling in Web Api 2


From previous topics we know that unhandled exceptions can be processed via exception filters but
there are some cases that exception filters can’t handle. Such as exception thrown from controller
constructor, exception from message handlers etc. or sometimes we need to handle all exception from a
single place. What should we do if above situations are create? We have to handle all these exceptions
globally and Asp.net Web Api provides a very convenient way to do that. We can do these by
implementing IExceptionHandler interface. This interface allows to catch exception from almost
everywhere in web api.

How to do it...
There are two facts for handling exceptions. The fact when we are able to send error response and the
fact where we can log exceptions. To handle exceptions globally we have to create two services:
IExceptionLogger and IExceptionHandler, to log and handle unhandled exceptions. The services are very
similar, with two main differences:
 We support registering multiple exception loggers but only a single exception handler.
 Exception loggers always get called, even if we’re about to abort the connection. Exception
handlers only get called when we’re still able to choose which response message to send.
The exception logger and handler service interfaces are simple methods that take respective context and
the structure of ExceptionHandler and the ExceptionLogger interface are as follows :
public interface IExceptionLogger
{
Task LogAsync(ExceptionLoggerContext context,
CancellationToken cancellationToken);
}

public interface IExceptionHandler


{
Task HandleAsync(ExceptionLoggerContext context,
CancellationToken cancellationToken);
}

We need to create base class for overriding purpose for these two interfaces. For logging,
the ExceptionLogger base class will ensure that the core logging method is only called once for each
exception. The ExceptionHandler base class will call the core handling method only for exceptions at the
top of the call stack, ignoring legacy nested catch blocks. And here is the code for abstract exception
handler which should be the base for Custom handlers:

public class ExceptionHandler : IExceptionHandler


{

public virtual void Handle(ExceptionHandlerContext context)


{
//can be overriden
}

public virtual Task HandleAsync(ExceptionHandlerContext context,


CancellationToken cancellationToken)

{
//can be overriden
}

public virtual bool ShouldHandle(ExceptionHandlerContext context)


{
//can be overriden
}

You are able to override the method responsible for handling the occurring exception and the base class
actually exposes the way to do it in both a synchronous and asynchronous way. And another important
thing is the Web Api exception handling pipeline supports a single handler. By ExceptionHandlerContext
the details of exception are reached to the handler. The ExceptionHandlerContext creates
ExceptionContext property by which it provides some key exception information such as
HttpActionContext, HttpRequestContext, HttpRequestMessage, HttpResponseMessage, or the actual
exception. Those can be used to log or handle the exception state of your Web API application
appropriately.
Ok let’s have some code. We are going to build an exception handler for BooksWebApi application.
Here we create a different class named ExceptionData. From this class we will generate an Id for each
exception and easily recognizable error messages. The ExceptionData class is look like as follows :

public class ExceptionData


{
public Guid Id { get; set; }
public string Message { get; set; }
public DateTime DateTime { get; set; }
public Uri RequestUri { get; set; }
}

The ExceptionHandler should be capable of returning a content-negotiated response. And it will use the
CreateResponse extension method off the HttpRequestMessage. the Web API pipeline will use a specific
response by setting the Result property. For our BooksApiExceptionHandler the code is as follows:

public class BooksApiExceptionHandler : IExceptionHandler


{
public override void Handle(ExceptionHandlerContext context)
{
var exceptionData = new ExceptionData
{
Id = Guid.NewGuid(),
Message = "An unexpected error occurred! Please use the ticket ID to
contact support",
DateTime = DateTime.Now,
RequestUri = context.Request.RequestUri

};
var response =
context.Request.CreateResponse(HttpStatusCode.InternalServerError, exceptionData);
context.Result = new ResponseMessageResult(response);
}
}

Here in this code the ResponseMessageResult is responsible for provide an existing


HttpResponseMessage to the client side. The exception will contain relevant data for the
exception as follows:

Status: 500 Internal Server Error


{
ErrorId: "3e6530ce-7530-40e9-8ec7-0aa60d0ed756",
Message: "An unexpected error occurred! ",
DateTime: "2015-11-30 T14:07:49.0218346+01:00",
RequestUri: "http://localhost:999/Booksapi/my"
}
Summary
Except above exception handling procedure, we can also create error log, Tracer for exceptions etc in
Asp.Net Web Api. Besides our above code and procedure we can handle exception in Web Api which is a
great feasibility for our development process.

You might also like