Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Wednesday, June 28, 2017

Few Interesting facts of Attribute routing

We of us know that Attribute Routing has introduced to enhance flexibility of routing in ASP.NET MVC. So, here is my ItemController which marked as “Item” using routeprefix attribute and GetItem(int Id) action is decorated using Route attribute. So, to invoke 
GetItem, the route is “/Item/1” 

    [RoutePrefix("Item")]
    public class ItemController : Controller
    {

        [Route("{id}")]
        public void GetItem(int Id)
        {

        }
    }

Now, let’s think some situation where we want to override behavior of RoutePrefix. We have defined GetItemInfo() action with Route attribute prefixed by “~/” which implies that we need to specify “Item” to invoke the action. So, the route to access GetItemInfo() is
      
    [RoutePrefix("Item")]
    public class ItemController : Controller
    {

        [Route("~/SpecialItem/{id}")]
        public void GetItemInfo(int Id)
        {

        }
    }

Set Global Default Route

We know that, in time of route initialization in config file we can specify default route. Here is another way to implement same. Just specify “~/” in any action to mark the action as default action.

So Route to access GetItemInfo() is : /

    [RoutePrefix("Item")]
    public class ItemController : Controller
    {
        [Route("~/")]
        public void GetItemInfo()
        {

        }
    }


Now, What if we mark more than one action as default action? You will experience following exception.


Set Default route to specific RoutePrefix

If we place Empty string(“”) to some action, it will mark as default route for that RoutePrefix. So, In following example GetItemInfo() is default route under “Item” RoutePrefix.

So, to Invoke GetItemInfo() the route is “/Item”

    [RoutePrefix("Item")]
    public class ItemController : Controller
    {
        [Route("")]
        public void GetItemInfo()
        {

        }
    }

Here is another way to set default route. 

  RoutePrefix("Item")]
  [Route("{action=GetItemInfo}")]
    public class ItemController : Controller
    {
        public void GetItemInfo()
        {
        }
    }

Route matching by pattern

Using attribute routing, we can pick route by pattern. Now, all routes ended with “info” suffix will map to GetItemInfo() action. So, one sample route could be “/Item/anyinfo”

[RoutePrefix("Item")]
   
    public class ItemController : Controller
    {
        [Route("{*info}")]
        public void GetItemInfo()
        {

        }
    }

Set priority to route

We know that if there are multiple action mapping to same route, we will get exception. To get rid of from this situation, we can specify “Order”. In following example we specified Order in “Route” attribute to action. The route “Item/get/id” is mapping to both GetItemInfo() and GetAnotherItemInfo().

public class ItemController : Controller
    {
        [Route("get/{id}", Order =0)]
        public void GetItemInfo(int Id)
        {

        }

        [Route("get/{id}", Order = 1)]
        public void GetAnotherItemInfo(int Id)
        {

        }

    }

If we do not specify “Order” it will throw this exception.


MVC, register low order route value at first, we Once we go with “item/get/1” it will hit GetItemInfo() action.




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.


Saturday, October 29, 2016

Custom formatter and data binding in MVC

The purpose of the article is to overcome such scenario where we want to handle custom data binding in MVC application.

We know that data binding and Request/Response processing is one of the key extensible point of MVC framework.

Custom Formatter

Let’s start with custom formatter. This is very useful when we want to send/get data structure other than JSON or XML. We know that MVC supports both data encoding scheme by default.   

Probably the other solution to red off the problem is just to prepare XML or JSON format of your data before send to API.
But the better solution could be writing your custom formatter and hook up in MVC framework.

Say, we have some comma separated information which we want to feed to API. In this example we will see how to process such value using custom formatter.


Here is our simplest DTO class.

   public class Person
    {
        public string Name { get; set; }
        public string Surname { get; set; }
    }

Now, we have created CommaFormatter which is derived from “BufferedMediaTypeFormatter”. The mime type is chosen in constructor.

public class CommaFormatter : BufferedMediaTypeFormatter
    {
        public CommaFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/colon"));
        }
        public override bool CanReadType(Type type)
        {
            if (type == typeof(Person) || type == typeof(List<Person>))
                return true;
            else
                return false;
        }
        public override bool CanWriteType(Type type)
        {
            if (type == typeof(Person) || type == typeof(List<Person>))
                return true;
            else
                return false;
        }

        public override object ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            List<Person> Obj = new List<Person>();
            Person p = null;
            StreamReader reader = new StreamReader(readStream);
            string str = reader.ReadToEnd();
            string []propArr = str.Split(',');
            foreach (var item in propArr)
            {
                string[] propAttribute = item.Split('|');
                p = new Person();
                foreach (var item1 in propAttribute)
                {
                    string[] propAttribute1 = item1.Split('=');
                    if (propAttribute1[0].ToLower().Trim().Equals("name"))
                    {
                        p.Name = propAttribute1[1];
                    }
                    if (propAttribute1[0].ToLower().Trim().Equals("surname"))
                    {
                        p.Surname = propAttribute1[1];
                    }
                }
                Obj.Add(p);
            }
            return Obj;
        }
    }


Now,It’s time to hook up the formatter in Global page ,so that it got register in MVC. 

GlobalConfiguration.Configuration.Formatters.Add(new CommaFormatter());

In Post method of API we are trying to pass list of “Person”

public class CustomController : ApiController
    {
        [HttpPost]
        public void Post(List<Person> p)
        {
          
        }
    }

Please make sure that the “Content-Type” is set in request header.


You can observer that the payload is as per our custom data format.

And it’s banded to action method.

Custom model binding

This is another way to bind unformatted fata to MVC endpoint. Just think one scenario where data is coming from query string. We know, that if key of query string matches with model property then MVC is intelligent enough to bind by default. But what if the query string does not match with model property?

The custom model binding comes into picture. We took simple Person model to demonstrate the example.

    public class Person
    {
        public string Name { get; set; }
        public string Surname { get; set; }
    }

Now, here we have created PersonModelBinder which is derived from DefaultModelBinder and override BindModel method.

In this method we are getting value of query string from request context and returning as concrete object of person model.

public class PersonModelBinder : DefaultModelBinder
    {
        public PersonModelBinder()
        {

        }
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var request = controllerContext.HttpContext.Request;
            string name = request.QueryString["name"];
            string surname = request.QueryString["surname"];
            return new Person { Name = name, Surname = surname };
        }
    }

Here is the procedure to hook up the custom formatter in MVC pipeline.

ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());

To receive data as parameter we have to use ModelBinder attribute

public class CustomController : Controller
    {
        public void Post([ModelBinder(typeof(PersonModelBinder))]  Person p)
        {
          
        }
    }

We are seeing that the value is binded in action.


Conclusion: In this two example we have seen how to handle custom data format in MVC. The formatter is useful when you don’t want to convert your data to XML or JSON prior to send to API and custom model binder is suitable when the amount of data is small and short enough to pass as query string.