So, following my previous post on implementing a custom ASP.NET Value Provider, here is another one.
Request Header Value Provider
Here is a totally useless requirement: add a Value Provider that would let you use your request headers in your actions without calling HttpContext.Current.Request
(or something equally unacceptable). This is actually absurdly simple, because we already have a convenient base class, NameValueCollectionValueProvider
, that takes a collection and provides its values to the unsuspecting Controller. So, the code is pretty simple:
public class RequestHeaderValueProvider : NameValueCollectionValueProvider {
public RequestHeaderValueProvider(ControllerContext controllerContext)
: base(controllerContext.HttpContext.Request.Headers,
CultureInfo.CurrentCulture) { }
}
public class RequestHeaderValueProviderFactory : ValueProviderFactory {
public override IValueProvider GetValueProvider
(ControllerContext controllerContext) {
return new RequestHeaderValueProvider(controllerContext);
}
}
Note that we need a ValueProviderFactory
again. And we need to register it in Global.asax as well:
ValueProviderFactories.Factories.Add(new RequestHeaderValueProviderFactory());
Now it's enough to name the action method parameter as the header you need, and you'll get the value automatically.
Writing a Test For It
So, I wasn't completely honest with you when I said it was completely useless. Apart from using it in RESTful apps, there is a pretty common need to get the referrer value, mostly for redirecting back to it as part of the Post-Redirect-Get routine. So, we can test two things (using Ivonna of course): that we have our referrer value as an argument, and that we are actually redirecting to it. Both are integration tests, and the second one is testing both our infrastructure and the actual Action
method, but who cares:
[Test]
public void TestHeaderProvider() {
var request = new WebRequest("/Sample/ActionUsingReferer")
{AutoRedirect = false};
const string previousurl = "/PreviousUrl";
request.Headers["Referer"] = previousurl;
var response = new TestSession().ProcessRequest(request);
Assert.AreEqual(previousurl,
response.ActionMethodParameters["referer"]);
Assert.AreEqual(previousurl,
response.RedirectLocation);
}
Notice that we have to disable the Autoredirection
feature of Ivonna: without that, we'll be testing the result of the redirection (quick poll: do you want this property to be false
by default?), rather than the original request. Notice that we are using the new MVC feature of Ivonna: the ability to get the action
method parameters.
Finally, here's the code that makes this test happy:
public ActionResult ActionUsingReferer(string referer) {
return Redirect(referer);
}
Unfortunately, header names like User-Agent
are not very C# friendly, so you might have to modify your code in order to be able to consume these headers as parameters named, say, user_agent
.