If you’re building WCF REST Services you may find that WCF’s OperationContext, which provides some amount of access to Http headers on inbound and outbound messages, is pretty limited in that it doesn’t provide access to everything and sometimes in a not so convenient manner. For example accessing query string parameters explicitly is pretty painful:
[OperationContract]
[WebGet]
public string HelloWorld()
{
var properties = OperationContext.Current.IncomingMessageProperties;
var property = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
string queryString = property.QueryString;
var name = StringUtils.GetUrlEncodedKey(queryString,"Name");
return "Hello World " + name;
}
And that doesn’t account for the logic in GetUrlEncodedKey to retrieve the querystring value.
It’s a heck of a lot easier to just do this:
[OperationContract]
[WebGet]
public string HelloWorld()
{
var name = HttpContext.Current.Request.QueryString["Name"] ?? string.Empty;
return "Hello World " + name;
}
Ok, so if you follow the REST guidelines for WCF REST you shouldn’t have to rely on reading query string parameters manually but instead rely on routing logic, but you know what: WCF REST is a PITA anyway and anything to make things a little easier is welcome.
To enable the second scenario there are a couple of steps that you have to take on your service implementation and the configuration file.
Add aspNetCompatibiltyEnabled in web.config
First you need to configure the hosting environment to support ASP.NET when running WCF Service requests. This ensures that the ASP.NET pipeline is fired up and configured for every incoming request.
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Note that this is a global setting and it will affect all of your WCF REST applications which can be problematic if some applications require and others explicitly don’t allow asp net compatibility.
Markup your Service Implementation with AspNetCompatibilityRequirements Attribute
Next you have to mark up the Service Implementation – not the contract if you’re using a separate interface!!! – with the AspNetCompatibilityRequirements attribute:
[ServiceContract(Namespace = "RateTestService")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RestRateTestProxyService
Typically you’ll want to use Allowed as the preferred option. The other options are NotAllowed and Required. Allowed will let the service run if the web.config attribute is not set. Required has to have it set. All these settings determine whether an ASP.NET host AppDomain is used for requests.
Be very careful with the NotAllowed and Requires settings as both of these will explicitly fail if the web.config setting does not match. I recommend you always use Allowed as it will not fail if the flag is missing or if it is set and so can still work regardless of the web.config setting. This can be a big concern if you have multiple WCF REST apps in the same IIS application.
Once Allowed or Required has been set on the implemented class you can make use of the ASP.NET HttpContext object.
When I allow for ASP.NET compatibility in my WCF services I typically add a property that exposes the Context and Request objects a little more conveniently:
public HttpContext Context
{
get
{
return HttpContext.Current;
}
}
public HttpRequest Request
{
get
{
return HttpContext.Current.Request;
}
}
While you can also access the Response object and write raw data to it and manipulate headers THAT is probably not such a good idea as both your code and WCF will end up writing into the output stream. However it might be useful in some situations where you need to take over output generation completely and return something completely custom. Remember though that WCF REST DOES actually support that as well with Stream responses that essentially allow you to return any kind of data to the client so using Response should really never be necessary.
Should you or shouldn’t you?
WCF purists will tell you never to muck with the platform specific features or the underlying protocol, and if you can avoid it you definitely should avoid it. Querystring management in particular can be handled largely with Url Routing, but there are exceptions of course. Try to use what WCF natively provides – if possible as it makes the code more portable. For example, if you do enable ASP.NET Compatibility you won’t be able to self host a WCF REST service.
At the same time realize that especially in WCF REST there are number of big holes or access to some features are a royal pain and so it’s not unreasonable to access the HttpContext directly especially if it’s only for read-only access. Since everything in REST works of URLS and the HTTP protocol more control and easier access to HTTP features is a key requirement to building flexible services.
It looks like vNext of the WCF REST stuff will feature many improvements along these lines with much deeper native HTTP support that is often so useful in REST applications along with much more extensibility that allows for customization of the inputs and outputs as data goes through the request pipeline. I’m looking forward to this stuff as WCF REST as it exists today still is a royal pain (in fact I’m struggling with a mysterious version conflict/crashing error on my machine that I have not been able to resolve – grrrr…).
Other Posts you might also like