This project is read-only.

Selecting response processor based on the query string

Topics: Web Api
Jan 25, 2011 at 12:58 PM

I have a WCF REST application which implements the Twitter API. Their XML and JSON serialisation differs from the out-of-the-box MS offerings, so I have custom seralisers which I invoke by returning Stream from the service methods, and explicitly passing typed results into them in those methods. The new WCF Web API looks promising as I would like to be able to insert them into the pipeline as ResponseProcessors and have better typed service methods. However, Twitter determines the response format from the query string rather than the request header, and it's very common for Twitter clients not to specify an Accept header at all. Is there any way to base choice of ResponseProcessor on something other than the Accept header's media types? I wondered about having a message inspector that modifies the request headers by inspecting the URL, but that seems clumsy, and I hope there's a better way.

I'm brand new to the APIs, so apologies if the answer to this is very obvious.

Jan 29, 2011 at 9:56 PM
Edited Jan 29, 2011 at 10:53 PM

Hi Nick

You can do this. Check Jon Galloway's post here for an approach of how to do this with the current bits. Look for the section titled "Un-bonus: anticlimactic filename extension filtering epilogue"

Basically you have to do 3 things.

1. Set your custom processor's SupportedMediaTypes to return empty collection thus making it response to all media types.

2. In the WriteToStream method check the uri extension for a match. For examle below is Jon's logic.

public override void WriteToStream(object instance, Stream stream, HttpRequestMessage request) 
    var contact = instance as Contact; 
    if (request.RequestUri.AbsoluteUri.EndsWith(".wav", StringComparison.InvariantCultureIgnoreCase) && contact != null) 
        var speech = new SpeechSynthesizer(); 
        string message = "{0} can't come to the phone right now. Try e-mail at {1} or on Twitter at {2}."; 
        speech.Speak(string.Format(message, contact.Name, contact.Email, contact.Twitter)); 

3. In the actual operation add a parameter to the uri template and then parse within the method to see if it has an extension.

[WebGet(UriTemplate = "{id}")] 
public Contact Get(string id, HttpResponseMessage response) 
    int contactID = !id.Contains(".")  
        ? int.Parse(id, CultureInfo.InvariantCulture)  
        : int.Parse(id.Substring(0, id.IndexOf(".")), CultureInfo.InvariantCulture); 
    var contact = this.repository.Get(contactID); 
    if (contact == null) 
        response.StatusCode = HttpStatusCode.NotFound; 
        response.Content = new StringContent("Contact not found"); 
    return contact; 

I am not saying this is ideal, but it does work :-) We are looking at an approach to make this much easier in the future.


Jan 29, 2011 at 10:48 PM

Hey Glenn,

Shouldn't that be 

response.Content = new StringContent("Contact not found"); 

unless you added some extension magic that I haven't found yet.

Jan 29, 2011 at 10:51 PM

That post used the older bits. Good point though! I will update.

Jan 30, 2011 at 4:13 PM

Many thanks guys - that is much better than returning Stream from all the service methods.