Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Allowing Access to HttpContext in WCF REST Services


:P
On this page:

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…).

Posted in ASP.NET  AJAX  WCF  

The Voices of Reason


 

Joe Brinkman
January 10, 2011

# re: Allowing Access to HttpContext in WCF REST Services

After using WCF REST for one project it is clear that it was an afterthought to WCF (and apparently even then it wasn't well thought out). While it is possible that you might want to host a REST based interface outside of the web context, the reality is that most users will never develop a REST based endpoint that is not hosted by a Web Server. Making the majority of users have to jump through extra hoops to get this context seems backwards. I would have much preferred if you had to do extra configuration to turn it off instead.

Rick Strahl
January 10, 2011

# re: Allowing Access to HttpContext in WCF REST Services

@Joe - I agree with you re: afterthought. It feels like the current implementation has been shoehorned to fit the WCF model and in the process doesn't provide neither the same reusability that other WCF services exhibit, nor the flexibility required to create a true REST service effectively.

To the credit of the WCF REST functionality - By default the installation in VS 2010 enables ASP.NET compatibility by setting the Config setting and attribute on the service implementation. Also the work that Glenn Block and Co. are doing is looking very promising to provide more complete functionality and more flexibility, although I'm skeptical that REST will ever be a good for a WCF service. Too many mismatches there - personally I use a home grown solution that's much easier to work with and doesn't feel shoehorned :-)

Nathan
January 11, 2011

# re: Allowing Access to HttpContext in WCF REST Services

I recently enabled the ASP.NET compatibility in our web.config, only to find out that another wcf service in our environment was throwing exceptions because it didn't have the AspNetCompatibilityRequirementsMode.Allowed attribute.

It seems reasonable for Microsoft to default the ASP.NET compatibility to false, but shouldn't the service default to AspNetCompatibilityRequirementsMode.Allowed instead of NotAllowed so that it won't throw an exception?

It was particularly frustrating for us since we didn't own the other wcf bits.

Rick Strahl
January 11, 2011

# re: Allowing Access to HttpContext in WCF REST Services

@Nathan - yeah this is yet another example where WCF in general falls flat - a lot of settings have global effect. This is one example the other is authentication - WCF REST 4.0 still only supports ONE authentication and anonymous accounts as one mode. You can't have both anonymous and Windows Auth for example. These sort of global settings are one of the main show stoppers in WCF IMHO.

If it was up to me I would not use WCF for REST dev, but customers often go with the tech that's in the box and so we have to go along... :-)

Louis Haußknecht
January 13, 2011

# re: Allowing Access to HttpContext in WCF REST Services

Rick, what framework in the .net - space would you recommend for a REST based webservices then?

Sam Meacham
January 13, 2011

# re: Allowing Access to HttpContext in WCF REST Services

I've created an open source library (restcake.net) that is essentially a drop in replacement for the WCF runtime for REST services. No config required in your webconfig. Just change your [ServiceContract] class so that it inherits from RestHttpHandler, and set up a route in your Global.asax. All your rest services will now work through the RestCake runtime, which uses the Json.NET serializer. It's very fast and very easy, might be worth a look. WCF REST and the DataContractJsonSerializer are just not worth it.

Rick Strahl
January 14, 2011

# re: Allowing Access to HttpContext in WCF REST Services

@Sam - Frankly I would tell you that you don't need a framework to build REST services. Nothing an HTTP handler can't do with a little bit of routing logic. FWIW, for REST services/requests I use the West Wind Toolkit CallbackHandler which makes it real easy to create a handler with methods that act as endpoints. The only thing missing from this is routing which you can set up separately - something to add for the future.

James
July 21, 2014

# re: Allowing Access to HttpContext in WCF REST Services

What would be nice is a way to access the query string dictionary in the same way you use the params keyword.

However, I guess that then doesn't map well to SOAP?
Does SOAP not have a concept of optional parameters?

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024