Posted on 5/9/2020 12:56:25 PM by Admin

Media Type Formatters in Asp.Net Web API

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.

Now ,wait and think, is only defining accept header and content type header enough? Obviously enough from client side but what about server. How server converts the .Net types into XML or JSON. Similarly how he converts 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.

Media Type Formatter
Media Type Formatter

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 LoadEmployee()
        {

            List Employees = new List(){
                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.

Role of media type formatter in get request
Role of Media Type Formatter during Get Request
Role of media type formatter in Post request
Role of Media Type Formatter during Post Request

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?

Modify the Register method in WebApiConfig in the App_Start folder and add below code segment into this to list out the default MediaTypeFormatters .


   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.

Default Media Type Formatters
Default Media Type Formatters

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, JsonMediaTypeFormatter and XmlMediaTypeFormatter, are the important ones. 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 .

Include the following line in Register() method of WebApiConfig.cs file in App_Start folder. This tells ASP.NET Web API to use JsonFormatter when a request is made for text/html which is the default for most 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, as 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.

Json Response for browser
Json Response from browser

Also, if you test it from fiddler, you will notice that the Content-Type is also set to application/json in the response header.

Content-Type
Content-Type