C#

how to handle errors in web api


ASP.Net Web API is a lightweight framework using this, you can build stateless RESTful services that run on HTTP/HTTPS.Exceptions are the errors that happen at runtime. Exception handling is the technique to handle this runtime error in our application code. If any error is thrown in web API that is caught, it is translated into an HTTP response with status code 500- "Internal Server Error".

These are the ways to handle the exceptions in asp.net web api.
    1.      HttpResponseException
    2.      Exception Filters
    3.      Exception Handler
    4.      HttpError

Here i am using student class for example first i create student model , you can copy and paste in IDE for practicle.
public class StudentModel
    {
        public int Id { get; set; }
        public string Email { get; set; }
        public string Name { get; set; }
    }
For data i am using method which return list but you can get from database also for real time.
public class StudentRepository
    {
        public List<StudentModel> GetList()
        {
            return new List<StudentModel>
            {
                new StudentModel {Id=1,Name="ABC",Email="ABC@gmail.com" },
                new StudentModel {Id=2,Name="XYZ",Email="xyz@gmail.com" },
                new StudentModel {Id=3,Name="RAM",Email="ram@gmail.com" }
            };
        }
    }





Using HttpResponseException

This exception returns any HTTP status code from your controller methods that you specify in the exception constructor. For example, the following method returns 404, Not Found, if the id parameter is not valid.
public class StudentController : ApiController
    {
       // return only status code in Exception
        public HttpResponseMessage Get(int id)
        {
            StudentRepository repository = new StudentRepository();
            var studentDetail = repository.GetList().Where(x => x.Id == id).FirstOrDefault();
            if (studentDetail == null)
            {
                //use of HttpReponseException class
                //in constructor we can pass any type of status
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
            return Request.CreateResponse(HttpStatusCode.OK, studentDetail);
        }
}


Exception in web api


You can also return any user define message along with status code , following example return status code with user define message.
  public HttpResponseMessage GetStudent(int id)
        {
            StudentRepository repository = new StudentRepository();
            var studentDetail = repository.GetList().Where(x => x.Id == id).FirstOrDefault();
            if (studentDetail == null)
            {
                //use of HttpReponseException class
                //in constructor we can pass any type of status
                var response = new HttpResponseMessage(HttpStatusCode.NotFound)
                {
                    //user define message
                    Content = new StringContent(
                        string.Format("Student detail  not found with id:- {0}", id)
                        ),
                    StatusCode = HttpStatusCode.NotFound
                };
                throw new HttpResponseException(response);
            }
            return Request.CreateResponse(HttpStatusCode.OK, studentDetail);
        }



Using Exception Filters

The exception filter can be able to catch the unhandled exceptions in Web API. This filter is executed when an action method throws the unhandled exception. Note that exception filter does not catch HttpResponseException exception because HttpResponseException is specifically designed to return the HTTP response.
To create an exception filter, you need to implement the IExceptionFilter interface. You can also create exception filters by extending the abstract class ExceptionFilterAttribute and then overriding the OnException method.
Note that the ExceptionFilterAttribute abstract class in turn implements the IExceptionFilter interface.
The following code snippet illustrates how you can create a custom exception filter by extending the ExceptionFilterAttribute class and then overriding the OnException method
//Create class and inherit from ExceptionFilterAttribute class
    public class CustomExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
           
            actionExecutedContext.Response = actionExecutedContext.Request
                        .CreateResponse(HttpStatusCode.InternalServerError,
                        "Some exception occure..please try later.");
            base.OnException(actionExecutedContext);
        }
    }

You should add the custom exception filter to the filters collection of the HttpConfiguration object.

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
            config.Filters.Add(new CustomExceptionAttribute());
config.Formatters.Remove(config.Formatters.JsonFormatter);
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

You can register your exception filters in one of the following three ways:
1.         At the action level
2.         At the controller level
3.         Globally

At Action Level

To apply the filter to a specific action, add the filter as an attribute to the action:
public class StudentController : ApiController
    {
       // Excetion Filter Attribute
       [CustomExceptionAttribure]
        public HttpResponseMessage Get(int id)
        {
            StudentRepository repository = new StudentRepository();
            var studentDetail = repository.GetList().Where(x => x.Id == id).FirstOrDefault();
           
            return Request.CreateResponse(HttpStatusCode.OK, studentDetail);
        }
}

At the controller level.

To apply the filter to all of the actions on a controller, add the filter as an attribute to the controller class:
// Excetion Filter Attribute at controller level
    [CustomExceptionAttribure]
    public class StudentController : ApiController
    {
//code here--
}

Globally

To apply the filter globally to all Web API controllers, add an instance of the filter to the GlobalConfiguration.Configuration.Filters collection. Exception filters in this collection apply to any Web API controller action.
  GlobalConfiguration.Configuration.Filters.Add(new CustomExceptionAttribure());
If you use the "ASP.NET MVC 4 Web Application" project template to create your project, put your Web API configuration code inside the WebApiConfig class, which is located in the App_Start folder:
public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
            config.Filters.Add(new CustomExceptionAttribute());
}
    }

Using Exception Handlers

Normally, exception filter is used to catch the unhandled exception. This approach will work fine but it fails if any error is raised from outside action. For example, if any error is raised in the following area then exception filter will not work.
          Error inside the exception filter.
          Exception related to routing.
          Error inside the Message Handlers class.
          Error in Controller Constructor.
Web API 2 provides a good alternative way to achieve global exception handling. Web API provides "ExceptionHandler" abstract class to handle exception.

public class GlobalExceptionHandler : ExceptionHandler
    {
        public override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            const string errorMessage = "An unexpected error occured";
            var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError,
                new
                {
                    Message = errorMessage
                });
            response.Headers.Add("X-Error", errorMessage);
            context.Result = new ResponseMessageResult(response);
            return base.HandleAsync(context, cancellationToken);
        }
    }
Same as exception filter, Exception handler is also required to be registered. ExceptionHandler is inheriting from IExceptionHandler interface and Web API has already this type of class registered so we just need to replace this class to our custom exception handler class because Web API doesn’t support multiple ExceptionHandler.
    config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
Using HttpError
The HttpError object provides a consistent way to return error information in the response body. The following example shows how to return HTTP status code 404 (Not Found) with an HttpError in the response body.
//for http error attribute
        public HttpResponseMessage GetStudent1(int id)
        {
            StudentRepository repository = new StudentRepository();
            var studentDetail = repository.GetList().Where(x => x.Id == id).FirstOrDefault();
            if (studentDetail == null)
            {
                string _message = string.Format("Student detail  not found with id:- {0}", id);
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, _message);
            }
            return Request.CreateResponse(HttpStatusCode.OK, studentDetail);
        }

CreateErrorResponse is an extension method defined in the System.Net.Http.HttpRequestMessageExtensions class. Internally, CreateErrorResponse creates an HttpError instance and then creates an HttpResponseMessage that contains the HttpError.
Notice that the HttpError was serialized to JSON in this example. One advantage of using HttpError is that it goes through the same content-negotiation and serialization process as any other strongly-typed model.


           

No comments:

Post a Comment