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.