Say what you will about how nice WebAPI is, but a few things in the internal APIs are not exactly clean to use. If you decide you want to access a few of the simple Request collections like Headers, QueryStrings or Cookies, you'll find some pretty inane and inconsistent APIs to retrieve values from them. It's not anywhere as easy as ASP.NET's simple Request.Headers[]/QueryString[]/Cookies[] collections. Instead you have to wade through various different implementations of nested IEnumerable collections which are used to return collections - presumably for multiple values which is the .0005% use case. Each one of these collections need to be accessed differently and not exactly in the way you'd expect from any other Web platform tool.
The syntax to use them is definitely on the verbose side and for me it always throws me for a few minutes on how to best dig into these collections to retrieve a single value. I hate utility code that stops me in my tracks like that, especially for something that should be so trivial.
I finally got tired of trying to remember how to exactly retrieve values from these collections. So, I finally broke down and added a few extension methods that make this job a little simpler using a few one liners.
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
namespace System.Web.Http
{
/// <summary>
/// Extends the HttpRequestMessage collection
/// </summary>
public static class HttpRequestMessageExtensions
{
/// <summary>
/// Returns a dictionary of QueryStrings that's easier to work with
/// than GetQueryNameValuePairs KevValuePairs collection.
///
/// If you need to pull a few single values use GetQueryString instead.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static Dictionary<string, string> GetQueryStrings(this HttpRequestMessage request)
{
return request.GetQueryNameValuePairs()
.ToDictionary(kv => kv.Key, kv=> kv.Value, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Returns an individual querystring value
/// </summary>
/// <param name="request"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string GetQueryString(this HttpRequestMessage request, string key)
{
// IEnumerable<KeyValuePair<string,string>> - right!
var queryStrings = request.GetQueryNameValuePairs();
if (queryStrings == null)
return null;
var match = queryStrings.FirstOrDefault(kv => string.Compare(kv.Key, key, true) == 0);
if (string.IsNullOrEmpty(match.Value))
return null;
return match.Value;
}
/// <summary>
/// Returns an individual HTTP Header value
/// </summary>
/// <param name="request"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string GetHeader(this HttpRequestMessage request, string key)
{
IEnumerable<string> keys = null;
if (!request.Headers.TryGetValues(key, out keys))
return null;
return keys.First();
}
/// <summary>
/// Retrieves an individual cookie from the cookies collection
/// </summary>
/// <param name="request"></param>
/// <param name="cookieName"></param>
/// <returns></returns>
public static string GetCookie(this HttpRequestMessage request, string cookieName)
{
CookieHeaderValue cookie = request.Headers.GetCookies(cookieName).FirstOrDefault();
if (cookie != null)
return cookie[cookieName].Value;
return null;
}
}
}
All methods return null if the key value is not found and only a single value is returned (the 99.99995% case).
Now I can see that for efficiency it might be better to read say the query string collection once and read several values out at once rather than re-reading the collection each time. But still this is something that WebAPI should handle internally. At the very least the internal representations of these collections should access in a similar fashion instead of returning crazy shit like IEnumerable<KeyValuePair<string,string>>.
Anyway, I hope this saves some of you some brain cycles - I know it will for me.
Other Posts you might also like