.NET Zone is brought to you in partnership with:

I am developer and technology maniac who is working on Microsoft and PHP technologies. I have ASP.NET MVP title and I hold MCAD, MCSD and MCTS certificates. When I have free time I usually play with new technologies, hack something, read books, participate in communities and speak in events. I am also active blogger and my ASP.NET blog is the place you can find some interesting reading about my discoveries and personal thoughts. Gunnar is a DZone MVB and is not an employee of DZone and has posted 140 posts at DZone. You can read more from them at their website. View Full User Profile

ASP.NET Web API: Query String-Based Content Formatting

04.24.2012
| 3502 views |
  • submit to reddit

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

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 opened 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
Published at DZone with permission of Gunnar Peipman, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)