ASP.NET Web API: Query string based content formatting

My previous post about Web API content negotiation showed how to add support for new content formats. As our API may have consumers who prefer query for data using GET requests we have to offer something for these dudes too. In this post I will show you how to make life easier for our Web API consumers by using query string mappings.

I will use media type mapping and formatter from my previous posting Extending content negotiation with new formats. We have to modify code a little bit because we need also single vCard download.

Media type formatter

Here is my media type formatter for vCard. It supports vCard format for single and multiple results. Multiple results are given to write method as IEnumerable<ContactModel>.

public class vCardMediaTypeFormatter : MediaTypeFormatter
{
   
public
vCardMediaTypeFormatter()
    {
        SupportedMediaTypes.Clear();
        SupportedMediaTypes.Add(
new MediaTypeHeaderValue("text/x-vcard"
));
    }

   
protected override bool CanWriteType(Type
type)
    {
       
return type == typeof(IEnumerable<ContactModel
>) ||
               type ==
typeof(ContactModel
);
    }

   
protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders
contentHeaders,
                                                
FormatterContext formatterContext, TransportContext
transportContext)
    {
       
return Task
.Factory.StartNew(() =>
        {
           
if (type == typeof(ContactModel
))
                WriteVCard((
ContactModel
)value, stream);
           
else
                WriteVCard((IEnumerable<ContactModel
>)value, stream);
        });
    }

   
private void WriteVCard(ContactModel model, Stream
stream)
    {
       
var buffer = new StringBuilder
();
        buffer.AppendLine(
"BEGIN:VCARD"
);
        buffer.AppendLine(
"VERSION:2.1"
);
        buffer.AppendFormat(
"N:{0};{1}\r\n"
, model.LastName, model.FirstName);
        buffer.AppendFormat(
"FN:{0} {1}\r\n"
, model.FirstName, model.LastName);
        buffer.AppendLine(
"END:VCARD"
);

       
using (var writer = new StreamWriter
(stream))
        {
            writer.Write(buffer);
        }
    }

   
private void WriteVCard(IEnumerable<ContactModel> contactModels, Stream
stream)
    {
       
var
enumerator = contactModels.GetEnumerator();
       
while (enumerator.MoveNext())
        {
            WriteVCard(enumerator.Current, stream);
        }
    }
}

Query string mapping

Now let’s say to our web application that contacts API support vCard also with GET requests. QueryStringMapping class will help us out. We just add correctly initialized query string mapping to vCard media type formatter.

var vcard = new vCardMediaTypeFormatter();
vcard.MediaTypeMappings.Add(
new VCardMediaTypeMapping
());
vcard.MediaTypeMappings.Add(
new QueryStringMapping("format", "vcard", "text/x-vcard"
));

GlobalConfiguration.Configuration.Formatters.Add(vcard);

One thing to notice – we made no changes to our API to add support for vCards and query string mappings. Our API provides only functionality and it doesn’t make any decision about output formatting.

Testing query string

Now it’s time to test our query string mapping. We don’t mess with AJAX-requests anymore because we can conveniently use out browser. If I want to download contact that has ID value 11 over Web API I have to use the following query string:

http://my-app/api/contacts/11/?format=vcard

I will also open IE developer tools to monitor traffic. This is what was returned to browser:

Single vCard response from Web API

But now something weird happens – browser asks if we want to open vCard we just requested. Let’s say yes. Here is what you should see on the screen:

vCard on desktop

This is good example about how we can use our API in “mixed” mode. We can exchange data between systems but we can also let user to handle some results directly.

Conclusion

Our API can be consumed by different AJAX-clients but now we also made our API easier to use for guys who can easily make GET-requests. By example, PHP guys can use fopen() to make GET-request to our API controller. As we saw we can also use those GET-requests to let end users handle formatted downloads.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    2 thoughts on “ASP.NET Web API: Query string based content formatting

    • August 8, 2012 at 2:08 pm
      Permalink

      Hi,
      Thanks for this post.
      Do you know if it is possible to do the same for xml and json?
      I would like to select the returned format with the URL rather than with the header “Accept: application/xml”

    • January 18, 2013 at 10:02 am
      Permalink

      Can we achieve Query String Mapping by doing some setting in web.config file?

    Leave a Reply

    Your email address will not be published. Required fields are marked *