Recently in my team, there’s been a lot of discussion about how we should go about implementing a service layer for various orthogonal behaviors. At the center of the conversation is the question of whether or not we should develop this layer using MVC or WCF. On first look, MVC paints a pretty compelling picture – particularly since the majority of our services will be consumed in a simple HTTP services fashion (Note: I’m intentionally avoiding the term RESTful service because these services will not necessarily be resource/noun focused – however, they will be plain old JSON or XML over HTTP – not something that requires a proxy in order to work with it). Specifically, here are the some of the things that makes MVC look appealing:
- It’s really easy – just create a controller and action method
- Friendly URLs ala core routing
- IIS hosted
- JSON formatting is as simple as returning the JSON action result from the action method
- It’s easy to leverage an IoC container – simply create/plug in a custom controller factory
So that’s a pretty good list. However, even with all of those benefits, I kept coming back to a couple problems with using MVC as a general purpose service layer.
- It tightly couples your service to a specific host (IIS)
- It tightly couples your service to protocol (HTTP)
- it tightly couples your service to an addressing scheme (URL)
Now I know that some of you are reading this and calling YAGNI on me – and that may be fair to some degree. However, for what will be publically facing services (which implies that there needs to be some degree of longevity), I’m hesitant to take a dependency on an underlying “service platform” (in quotes since MVC wasn’t really meant to be this) that takes so many dependencies on things that I consider to be an architectural style (remember, it wasn’t that long ago that SOAP was the last thing we would ever need – and DCOM/CORBA before that). And technically, I’m not really talking about building anything based on unknown future requirements, but on choosing a platform on which to take a dependency.
Philosophically, I’m a big fan of WCF because as one of its key characteristics, it decouples the programming model (the service definition) from both the networking stack that exposes and pipes data into the service and from the process that hosts and manages the service. However, the initial versions of WCF provided all of this philosophical goodness at a cost – and that cost was complexity – particularly in the area of the host and network stack configuration. And that complexity grew pretty significantly the further off the path you traveled.
That said, with each successive release of WCF, the level of complexity in configuration has been shrinking – to the point where as of WCF 4, the configuration piece has dwindled away to almost nothing.
At any rate, like I mentioned, I wanted to see whether I could build simple JSON over HTTP services in a way that leveraged all of WCF’s philosophical goodness but would give me the simplicity of development that I would find doing it in MVC. More specifically, here’s what I was testing for:
- Standard WCF programming model
- JSON by configuration
- Use of IoC to resolve the service graph
- Hosted in IIS
- Friendly URLs
Jumping right in, WCF has a really straightforward programming model. It centers around the use of .NET interfaces decorated with a few attributes – these (along with some configuration around address and network stack) are exposed as WCF endpoints – and classes that implement one or more of those interfaces – these are WCF services and are the smallest units when it comes to hosting. The big idea here is that by using plain old .NET constructs, you can completely decouple your service logic and even contracts from all the details around hosting it and exposing it to the network. I started out in developing my service against this standard programming model.
As you can see, I’ve got a standard service contract with one operation. The WebGetAttribute allows me to specify a URI template with parameter placeholders. It’s worth noting here that this doesn’t give us complete MVC-ish friendly URLs – this is still relative to the service address, which if it’s hosted in IIS is that *.svc file. However, as I’ll show in a second, WCF 4 helps us remedy this little bit of trailing ugliness. Additionally, I’ve declared my message formatting in the WebGetAttribute class. I suspect that this can actually be externalized to config, but I haven’t figured out how to do this yet, and and attribute is still less invasive than returning a JsonActionResult in MVC – so for now, that’s what I’m going with.
The service itself is a pretty straightforward implementation of this interface – with one exception..
Notice that I have added a parameter to my constructor which declares that my service has a dependency on a concrete implementation of IPersonRepository. One of the things that I love about MVC is how straightforward it is to create a custom ControllerFactory that can use an IoC container to resolve a controller’s entire dependency graph. As such, I wanted to make sure that I could do the same thing in WCF. Early on in my searching, I was very fortunate to come across a 2 part blog series on doing just this. I have adapted the source just a bit to use Windsor and to account for a thing or 2 in WCF 4, but the bulk of the code (and my sincerest thanks) go to Fabio Cozzolino.
In short, the ControllerFactory equivalent in WCF is called the instance provider, and it’s any class that implements IInstanceProvider. Here’s an instance provider that’s built to use a Windsor container:
I would elaborate, but there’s just not that much of interest going on here. The instance provider is constructed with the container itself and the service type. When asked, it turns around and asks the container to resolve the dependency graph and create an instance of the service type. What’s more interesting is how the instance provider gets plugged in so that it can do its thing.
In the same way that ASP.NET (and MVC by extension) has a request pipeline, WCF has a channel stack. However, unlike the case of ASP.NET, the WCF channel stack was meant to work across a myriad number of protocols and network topologies – as such, it’s a great deal more extensible – and that extensibility can sometimes bring with it some additional complexity. In this case, that complexity exists in the form of a couple extra points of indirection – the first of which is a service behavior.
The purpose of my service behavior is simply to iterate through each endpoint in my service and set the endpoint’s instance provider to a new instance of my WindsorInstanceProvider, passing it an instance of my container (which I supply in the behavior’s constructor). I’m only doing this for custom endpoints – not for the metadata endpoint sometimes added somewhat transparently by a different behavior. It’s also worth pointing out that with WCF 4, I need to add a second type of metadata endpoint, IHttpGetHelpPageAndMetadataContract (I fully expect that we’ll see interface names that are complete sentences before long), to the exclusions list.
So you can now see where the instance provider comes from, but what about the container itself? And where is the behavior wired up. Enter the custom service host and custom service host factory First the factory:
As you can see, this is the point at which I’m actually creating the container. When asked to create the service host, I simply create and return an instance of my custom service host and pass my container to it. My service host, then, takes care of wiring up the behavior and you already know the rest of that story.
So, the chief complaint that I’ve heard about WCF is how painful the XML configuration is – here’s the great part – in WCF 4, the configuration is insanely straightforward – here’s the configuration to get this all up and going (keep in mind that I would actually like to externalize more of my current sample into configuration – but this should give you a pretty good sense of how much has been improved in this area).
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> <standardEndpoints> <webHttpEndpoint> <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/> </webHttpEndpoint> </standardEndpoints> </system.serviceModel>
So deploying to IIS is as simple as building this into an *.svc file and writing a directive to point to my custom service host factory. But then I still end up with odd-looking URLs like http://localhost/SimpleWCFTestHost/PersonService.svc/Find/Howard. It would be even better if I could just drop that *.svc file and have completely clean URLs – just like I can do with MVC. Firstly, remember that MVC doesn’t actually give you clean URLs – it simply plugs into the new core routing engine that’s backed into ASP.NET 4. And that’s exactly the capability that WCF 4 gives you as well. To light this up, all I had to do was add this to my global.asax.cs file.
This simple entry and I now have the ability to address my service as http://localhost/SimpleWCFTestHost/Find/Howard. Had I wanted to give the service its own path segment, I could have specified my desired segment name as the first parameter to the ServiceRoute constructor.
After this experiment, WCF is at this point in time the more natural choice in my mind for building a general service layer. Note – I’m not saying that you shouldn’t use MVC to create services for the AJAX components on your pages. Just that if those services grow in scope such that they have other clients than your view, it might be time to look at a truer service platform – with WCF 4, it’s not *that* much more complicated.
Finally, I stumbled across a multi-part series that’s currently being developed on this topic over at The .NET Endpoint – It looks like they are just on part 4 of 12, so that’s only around the first 30 minutes of the movie – there’s still plenty of great stuff to come!