Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Response Headers on Media Type Formatter for ASP.NET Web API

I have created an ASP.NET web API controller that is returning a strongly typed object on an action, as follows:

// GET api/iosdevices/5
public iOSDevice Get(string id) {
  return new iOSDevice();
}

I have created a BufferedMediaTypeFormatter to handle the type iOSDevice:

public class iOSDeviceXmlFormatter : BufferedMediaTypeFormatter
{
    public iOSDeviceXmlFormatter() {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
    }

    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content) {
        content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
        iOSDevice device = (iOSDevice)value;
        using (XmlWriter writer = XmlWriter.Create(writeStream)) {
            writer.WriteStartElement("iOSDevice");
            if (device.identifierForVendor != Guid.Empty) {
                writer.WriteElementString("identifierForVendor", device.identifierForVendor.ToString());
                writer.WriteElementString("userInterfaceIdiom", device.userInterfaceIdiom);
                writer.WriteElementString("systemName", device.systemName);
                writer.WriteElementString("systemVersion", device.systemVersion);
                writer.WriteElementString("model", device.model);
            }
            writer.WriteEndElement();
        }
        writeStream.Close();
    }
}

My problem is when I catch type "text/html" (e.g. someone attempts to access the API from his or her web browser), the response type is "text/html" instead of "application/xml". I want to override the response type so that the user gets a response that is "application/xml" instead of "text/html".

I cannot in the ApiController type get access to the "Response" property that is on regular MVC controllers and I am at a loss. How do I override the response type for this action that is being handled by a media type formatter?

EDIT: HELPFUL NOTE

I was trying this previously:

var response = Request.CreateResponse<iOSDevice>(HttpStatusCode.Accepted, device);
response.Headers.Remove("Content-Type");
response.Headers.Add("Content-Type", "application/xml; charset=utf-8");
return response;

And it claimed I was "misusing" the headers.

But when I used Filip's example below of setting Content directly, it worked!

var response = Request.CreateResponse();
response.Content = new ObjectContent<iOSDevice>(device, new iOSDeviceXmlFormatter());
return response;
like image 884
Allison A Avatar asked Jan 07 '13 19:01

Allison A


People also ask

How do I change media type formatter in Web API?

The media type determines how Web API serializes and deserializes the HTTP message body. Web API has built-in support for XML, JSON, BSON, and form-urlencoded data, and you can support additional media types by writing a media formatter. To create a media formatter, derive from one of these classes: MediaTypeFormatter.

How do we specify response data type while making the request to Web API?

Web API converts request data into CLR object and also serialize CLR object into response data based on Accept and Content-Type headers. Web API includes built-in support for JSON, XML, BSON, and form-urlencoded data. It means it automatically converts request/response data into these formats OOB (out-of the box).

Which property returns all the formatter in Web API?

Configuration. Formatters returns MediaTypeFormatterCollection that includes all the formatter classes. The above example returns names of all the formatter classes as shown below.

What is the default data return format in Web API?

By default Web API returns result in XML format.


1 Answers

When you write to stream in the formatter, headers have been already sent.

You can do this:

    public HttpResponseMessage Get(string id) {
    {
        var value = new iOSDevice();
        var response = Request.CreateResponse();
        response.Content = new ObjectContent(typeof(iOSDevice), value, new iOSDeviceXmlFormatter());
        //set headers on the "response"
        return response;
    }

or you can do this (add this method to your formatter):

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, string mediaType)
    {
        base.SetDefaultContentHeaders(type, headers, mediaType);
        headers.ContentType = new MediaTypeHeaderValue("application/xml");
    }

Here is an example on how I used the SetDefaultContentHeaders with a custom formatter: http://www.strathweb.com/2012/09/generate-kindle-mobi-ebooks-with-your-asp-net-web-api/

   public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
   {
      if (CanWriteType(type) && mediaType.MediaType == supportedMediaType)
      {
         headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
         headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
         headers.ContentDisposition.FileName = "ebook.mobi";
      }
      else
      {
         base.SetDefaultContentHeaders(type, headers, mediaType);
      }
   }
like image 161
Filip W Avatar answered Sep 18 '22 10:09

Filip W