A friend of mine who is involved in a local start-up here in MPLS was talking to me about how his start up is building their web api. Their start-up is a mobile application that has a back end data store that they’re communicate with via a REST-esque API build using ASP.NET MVC, hosted on Azure. He told me that they were placing values into the http headers and then pulling them out on the other side. Upon asking him how he was doing it, he said something to the sort of “We just pull them out of the Request.Headers collection”. It made sense and was easily the KISS approach to the problem, right? That’s what I thought until an idea hit me smack dab in the face. ASP.NET MVC’s IValueProvider interface is a perfect use case for this.
KISS with ASP.NET MVC Value Providers
Value providers in MVC do just that … provide values. By implementing the IValueProvider interface you can define how MVC should provide values to your MVC app. As an example, if you have a view model that is the only parameter to your action, then you are expecting it to get hydrated via the post values, form values, querystring,etc. The hydration of your view model is all done by various value providers. Each value provider tries to find values to push into the view model for you. If it can find some values, it will. Which is why sometimes you can post 3/4 values and the other 1/4 value Some of the built in providers are:
- HttpFileCollectionValueProvider
- RouteDataValueProvider
- FormValueProvider
- QueryStringValueProvider
- …and more
However, there is not a HeaderValueProvider that comes with ASP.NET MVC out of the box. Therefore I needed to create one.
The HeaderValueProviderFactory & HeaderValueProvider
The class is below:
public class HeaderValueProviderFactory : ValueProviderFactory { public class HeaderValueProvider : IValueProvider { private readonly NameValueCollection _headers; public HeaderValueProvider(NameValueCollection headers) { _headers = headers; } public bool ContainsPrefix(string prefix) { return _headers.AllKeys.Any(x => x.Contains(prefix)); } public ValueProviderResult GetValue(string key) { if (_headers == null) { return null; } var val = _headers.GetValues(key) == null ? null : _headers.GetValues(key).FirstOrDefault(); return val != null ? new ValueProviderResult(val, val, CultureInfo.CurrentCulture) : null; } } public override IValueProvider GetValueProvider(ControllerContext controllerContext) { return new HeaderValueProvider(controllerContext.HttpContext.Request.Headers); } }
**Update**: I did not realize I could have inherited from NameValueCollectionValueProvider until I had already written this. While this works, you may want to re-write this to inherit from NameValueCollectionValueProvider, as Request.Headers is a NameValueCollection.
This code will grab the header values from the Request.Headers and then turn them into ValueProviderResults if a name match is found.
This is registered into the application in the Global.asax.cs file like so:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ValueProviderFactories.Factories.Add(new HeaderValueProviderFactory()); RegisterRoutes(RouteTable.Routes); }
Now, when a value comes in from the headers on a request the values will be mapped accordingly.
How To Functionally Test This Beast (to make sure it makes sense)
You’ll need an ASP.NET MVC project. I created the default File, New MVC project and then dropped the above code into the app. I then opened the AccountController.cs file and changed the Register() action to the following to simulate a JSON api:
[HttpPost] public ActionResult Register(RegisterModel x) { if (ModelState.IsValid) { this.ControllerContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.OK; return Json("Awesome!"); } this.ControllerContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.NotAcceptable; return Json("Fail!"); } <div></div>
Then I fired up FireFox and opened up the wonderful Poster plugin. This plugin allows you to create GET/POST/DELETE/PUT requests with various values, headers, as well as file posts. Its super simple and great for playing/testing web API’s. I’ve used it when building Eventdroid, Geowatchdog, barcodes.io, and many other projects for various clients.
You’ll need to know the property names of the RegisterModel in order to do the testing. The RegisterModel is the only parameter to the Register action on the AccountController. The properties are:
- UserName (string)
- Email (string)
- Password (string)
- ConfirmPassword (string)
Also notice how the data annotations are on this register model … yes… those will still work with the WEB api stuff we’re going to test (way cool).
Build the project, and place a breakpoint on the Register action in the AccountController. Then open up poster and type in the following (click for larger image):
Notice how I’ve only put in ONE header value “UserName”. I’m testing that the RegisterModel’s “UserName” property will get populated using the HeaderValueProvider and nothing else will get populated.
Now click, the POST button and you’ll see Visual Studio break on your breakpoint. Expand the RegisterModel’s model (in this case I’ve renamed it to x) and you’ll see something like this (click for larger image):
Notice how the model now has the username filled in? Cool! That came from the header collection in the Request! Also, if you debug down to the next couple of lines, you’ll notice how the ModelState.IsValue equates to false. So the DataAnnotations still work. See below:
If you let the program run the controller will return a status code of “Not Acceptable” (406) and will return a value of “Fail” via json. This result is captured in Poster, in a new window as shown below:
Now, lets make sure all of our required fields are filled in. You could do the following and populate the entire model via Poster in a POST like so:
Press the POST button and walk through the code and you’ll noticed that the ModelState is valid and the response looks like this in POST:
The result is a HTTP 200 (OK) and the json result is “Awesome!”
You can now pass values through the headers and they’ll get hydrated into your models.
So How Do These Value Providers Work?
At a high level, they’re chained together and each value provider will provide “what it can”. Lets take a look at a different example. Lets assume a company asks you to build an API that required the UserName, Password and ConfirmPassword be passed in via the headers, but the email MUST be passed in via the QueryString. The View model must be hydrated by then. So how would this work? Lets open up poster and make it look like this:
Look at the URL, you’re now passing in the email via the QueryString, the rest of the parameters are all passed in via http headers. If you press the POST button and still have a breakpoint set (and you’re still debugging) you’ll notice that the model is fully hydrated. See my debug window:
You might be wondering – How’s that possible?
The value providers are taking turns hydrating the data that they can handle. Therefore, the HeaderValueProvider fufilled the UserName, Password and ConfirmPassword properties while the QueryStringValueProvider provided the email.
You can mix and match values from all over the place. Headers, form variables, querystring, file post collections, or roll your own value provider.
Now that my buddy has this code, he no longer has to manually scrub the request for the header values he’s after. He creates his POCO’s and drops them into the action and he’s off to the races. 🙂