In the previous article, we have learnt, that a client can specify media types in the accept header to tell the server in which format of the resource, he is interested in.
Also, the client can specify the Content Type ,to tell the format of data, he is sending to the server or to tell the server the format of the entity being carried by the http message in the request message body, so that the server could process the request easily.
Now ,wait and think, is only defining accept header and content type header enough? Obviously enough from client side but what about server. How does server convert the .Net types into XML or JSON. Similarly how does he convert the entity which are in XML or JSON format in http message body into .Net types, so that it could be processed by Web API controller.
The Answer is, Media Type Formatters. A Media Type Formatter is an object of type MediaTypeFormatter , which is responsible for serialization in the Asp.Net web API pipeline. Here, serialization means translating .Net types into a format that can be transmitted over Http like JSON or XML or translating the entity (in post request as request message body) into .Net types.
Now let's take some examples. Suppose there is a web Api controller having two action methods ,the first one returns an Employee object while the second save an employee object into database.
public List<Employee> LoadEmployee()
{
List<Employee> Employees = new List<Employee>(){
new Employee(){Id=1,Name="Sachin",Salary=600000},
new Employee(){Id=2,Name="Arjun",Salary=350000},
new Employee(){Id=3,Name="Vikash",Salary=500000},
new Employee(){Id=4,Name="Abhijit",Salary=45000},
};
return Employees;
}
public HttpResponseMessage Post([FromBody] Employee employee)
{
try
{
using (EmployeeDBContext db = new EmployeeDBContext())
{
db.Employees.Add(employee);
db.SaveChanges();
var message = Request.CreateResponse(HttpStatusCode.Created, employee);
message.Headers.Location = new Uri(Request.RequestUri +employee.Id.ToString());
return message;
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
public HttpResponseMessage GetAllEmployeeById(int Id)
{
try
{
Employee emp = LoadEmployee().Where(x => x.Id == Id).SingleOrDefault();
if(emp!=null){
return Request.CreateResponse(HttpStatusCode.OK,emp);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound,"Employee with id " +Id+ " Not found");
}
catch
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
If you are not able to understand the post method currently, don't worry ,in the next article we will learn CRUD operation with entity framework. Here, you should only focus in learning the media type formatter.
Now ,Lets run the application and perform a get and post request with fiddler.
Now , Your next question should be ,is there only two built-in Media Type Formatters ,the JsonMediaTypeFormatter and XMLMediaTypeFormatter are available in Web API, the answer is No, Actually ,Web API includes four built-in Media Type Formatters, but the JsonMediaTypeFormatter and XMLMediaTypeFormatter are the important ones.
How to Know which are the four built-in Media Type Formatters and why the JsonMediaTypeFormatter and XMLMediaTypeFormatter are only the important ones?
If you want to list out all available MediaTypeFormaters, then go to App_Start folder and open your webApi.Config file and Add below lines of code in the Register() method .
foreach(var formatter in config.Formatters)
{
Trace.WriteLine(formatter.GetType().Name);
Trace.WriteLine("\tBase: "+formatter.GetType().BaseType.Name);
Trace.WriteLine("\tCanReadType: "+formatter.CanReadType(typeof(Employee)));
Trace.WriteLine("\tCanWriteType: " + formatter.CanWriteType(typeof(Employee)));
Trace.WriteLine("Media Types :"+string.Join(",",formatter.SupportedMediaTypes));
}
Note:-Like Debug ,Trace is used to provide information about the performance of an application either during application development, or after deployment to production, which are found in the namespace System.Diagnostics, so don't forget to import this namespace.
Now, run the application , and look at the output window of your application, you will get below output.
As ,you can see the last two Media Type Formatters can't write any Type, so from serialization point of view they are least important or simply can be ignored. The first two, that is "JsonMediaTypeFormatter" and "XmlMediaTypeFormatter", are the important ones which we need frequently. They are the media formatters that produce JSON and XML resource representations in the response also translate the request message body into .Net types.
Can we get JSON representation back ,when request is made from the browser?
we know a browser want to receive data in the format of html ,as the browser understands the html best. So, when the request is made from browser, by default the accept header is set to text/html.And the web API returns XML by default when the Media Type is text/html.
So,the following answers which are not so good ,can work.
1.The simplest answer is to change the default formatter for Accept:text/html to return Json .
Now, Go to App_Start folder and open webApiConfig.cs file, there you will find a Register Method, add following lines of code in that method. With this code, we are actually telling ASP.NET Web API to use JsonFormatter when a request is made for text/html, which is the default media-type for most of the browsers.
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));
2. Completely remove the XML formatter, forcing ASP.NET Web API to return JSON by default.
config.Formatters.Remove(config.Formatters.XmlFormatter);
• Obviously the second solution is the worst, because after that , ASP.NET Web API will always return Json irrespective of the Accept header value in the client request, which is very wrong.
• The first solution is bad if not worst, cause, here we are telling the web API to use Json Formatter ,but we are not telling to set the Content-Type to Json while sending the request. so even if ,the web Api will send the Json representation back, the Content-Type header of the response is set to text/html which is misleading.
3.The Best solution is to create a custom Json Formatter.
Include the following class in the WebApiConfig.cs file in App_Start folder.
public class CustomJsonFormatter : JsonMediaTypeFormatter
{
public CustomJsonFormatter()
{
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.ContentType = new MediaTypeHeaderValue("application/json");
}
}
Now , Register this Formatter in the Register() method of webApi.config class.
config.Formatters.Add(new CustomJsonFormatter());
your complete code should look like below.
namespace MyFirstAPIProject
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.Formatters.Add(new CustomJsonFormatter());
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class CustomJsonFormatter : JsonMediaTypeFormatter
{
public CustomJsonFormatter()
{
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.ContentType = new MediaTypeHeaderValue("application/json");
}
}
}
Now run the application ,you will get Json representation back as shown below.
Also, if you test it from fiddler, you will notice that the Content-Type is also set to application/json in the response header.