Working with Query Strings

Topics: Web Api
May 26, 2011 at 9:10 PM
Edited May 26, 2011 at 9:11 PM

Imagine something like this:

GET /designs?color=Red&Style=Fancy&designer=Rob&offset=20&limit=10

What is the best way to consume the query string parameters? In my case, there are a lot of possibilities. I can get the query string from the Request Uri and parse it out myself, but I'm wondering if there is an easier way.

May 26, 2011 at 9:49 PM
Edited May 26, 2011 at 9:51 PM

You can use a message handler to convert the query string to a strongly typed object in the message pipeline, here is an example.

Type I'm binding to"

    [DataContract]
    public class MatchQuery
    {
        [DataMember]
        public int WinnerId { get; set; }

        [DataMember]
        public int LooserId { get; set; }
    }

Message handler:

   public class MatchQueryHandler : HttpOperationHandler<int, int, MatchQuery>
    {
        public MatchQueryHandler()
            : base("matchQuery")
        {
        }
        public override MatchQuery OnHandle(int WinnerId, int LooserId)
        {
            return new MatchQuery { WinnerId = WinnerId, LooserId = LooserId };
        }
    }

Factory needed to get the handler in the pipeline {see note at bottom}:
public class MatchHttpOperationHandlerFactory : HttpOperationHandlerFactory
    {
        public MatchHttpOperationHandlerFactory(IEnumerable<MediaTypeFormatter> mediaTypeFormatters)
            : base(mediaTypeFormatters)
        {
        }

        protected override Collection<HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
        {
            Collection<HttpOperationHandler> handlers = base.OnCreateRequestHandlers(endpoint, operation);
            if (operation.InputParameters.Any(p => p.Type == typeof(MatchQuery))) ;
            {
                handlers.Add(new MatchQueryHandler());
            }
            return handlers;
        }
    }

Resource signature:
       [WebGet(UriTemplate = "GetMatchST?WinnerId={WinnerId}&LooserId={LooserId}")]
        public HttpResponseMessage GetMatchST(MatchQuery matchQuery)
        {
            var body = string.Format("WinnderId {0} LooserId {1}", matchQuery.WinnerId, matchQuery.LooserId);
            var response = new HttpResponseMessage();
            response.Content = new StringContent(body, Encoding.UTF8, "text/plain");
            return response;

            //return query;
        }

Code in the Global.asax to wire it up
            var config = HttpHostConfiguration.Create().SetOperationHandlerFactory(new MatchHttpOperationHandlerFactory(new MediaTypeFormatter[0]));
            RouteTable.Routes.MapServiceRoute<MatchResource>("Match", config);

There is an example of this in the unit tests of the WCF Code, but not in the samples.  Also Glenn Block mentioned a change in a previous post that would eliminate the need for the HttpOperationHandlerFactory. So it could be wired up like this. I didn't get the code to do this.
var builder = HttpHostConfiguration.Build().
  AddRequestHandlers((h,o)=>h.Add(new MatchQueryHandler(o));

May 27, 2011 at 2:25 AM

I don't think that will work for my scenario. But, that's really great information I'm sure I'll use elsewhere. Thanks! In my situation, I have a pretty advanced query situation where I might have any combination of a dozen or so parameters. I think the easiest way for me to handle it in code would be to get the qs as a dictionary. I didn't know if there was anything to do that or not built in. If not I'm sure I can find code to parse into that format from the Uri. I just didn't want to replicate it if it was already in the framework somewhere.

May 27, 2011 at 5:23 AM

I believe there is an OperationHandler in the request pipeline that will convert query string parameters into a JsonValue object.  Try adding a JsonValue object to your GET signature and see if the query string parameters magically appear in the JsonValue object.