Saturday, November 12, 2016

Extensible point of MVC: Custom response type in MVC and WebAPI


We know that MVC has many extensible point where we can hook up our custom code and change normal behavior of framework. Those implementations are really helpful when default framework is not able to meet our requirement.


In this article we will implement custom return type both in MVC and WebAPI. Those implementation could be helpful when we want to modify return type based on application’s demand. 

Custom return type in MVC

We know that ActionResult is base class of all return type in MVC. Return type like ViewResult, JsonResult , EmptyResutl etc are derived from ActionResult. We can derive our return type from ActionResult class as well.

Let’s think some use case where we want to limit return items in response message. For example we have list of objects and on demand we will decide how many objects we will return.
Though there are many ways like result filter , OData are there to implement such scenario but we can use custom response type too to implement.

Here we have LimitResult class which is derived from ActionResult. Within constructor we care filtering out items based on value of “Count”. 


public class LimitResult : ActionResult
    {
        Dictionary<int, Person> _disc = new Dictionary<int, Person>();
       
        public LimitResult(List<Person> list, int Count)
        {
            foreach (var item in list.Take(Count))
            {
                _disc.Add(item.Id, item);
            } 
        }
        public override void ExecuteResult(ControllerContext context)
        {
            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = "application/json";
            response.Write(JsonConvert.SerializeObject( _disc));
        }
    }

Now, We will use the custom class as response from action.


    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            List<Person> person = new List<Person>();
            person.Add(new Person { Id = 1, Name = "Sourav" });
            person.Add(new Person { Id = 2, Name = "Kayal" });

            return new LimitResult(person , 1);
        }
    }

We are seeing that only one item has returned because we set that only 1 result is allowed in response.


Custom Result in WebAPI 2

We know that Web API 2 supports IHttpActionResult as type. Though we can use HttpResponse as return type. In this example we will implement IHttpActionResult in our custom response class. Here we have wrap ForbiddenResult class and InternalServerErrorResult class by CustomResultApiController class.

So, the CustomResultApiController looks like a package of custom response type. 

public abstract class CustomResultApiController : ApiController
    {
        public class ForbiddenResult : IHttpActionResult
        {
            private readonly HttpRequestMessage _request;
            private readonly string _reason;

            public ForbiddenResult(HttpRequestMessage request, string reason)
            {
                _request = request;
                _reason = reason;
            }

            public ForbiddenResult(HttpRequestMessage request)
            {
                _request = request;
                _reason = "Forbidden";
            }

            public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
            {
                var response = _request.CreateResponse(HttpStatusCode.Forbidden, _reason);
                return Task.FromResult(response);
            }
        }


        public class InternalServerErrorResult : IHttpActionResult
        {
            private readonly HttpRequestMessage _request;
            private readonly string _errormessage;

            public InternalServerErrorResult(HttpRequestMessage request, string error)
            {
                _request = request;
                _errormessage = error;
            }

            public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
            {
                var response = _request.CreateResponse(HttpStatusCode.InternalServerError, _errormessage);
                return Task.FromResult(response);
            }
        }

    }

The IHttpActionResult interface contains ExecuteAsync() function and we have implemented in both classes.

Here is how, we can use our custom classes as response object.

public class HomeController : CustomResultApiController
    {
        [System.Web.Http.HttpGet]
        public IHttpActionResult Forbidded()
        {
            return new ForbiddenResult(Request, "My Custom Reason");
        }
    }

We are seeing that the response message is embedded in body of response object.
In same way we can invoke InternalServerErrorResult.

[System.Web.Http.HttpGet]
        public IHttpActionResult InternalError()
        {
            return new InternalServerErrorResult(Request, "My Custom Error message");                }


Conclusion:Custom response type is really helpful when you want to override default behavior of frameworks return type.


No comments:

Post a Comment