Jump to Integration with Visual Studio
For most developers, Visual Studio is the best tool for the job. And due to a variety of factors, it is also often the only one. It comes with a plethora of project templates to get a developer started or to aid a seasoned professional. Regrettably, the templates are often oversimplified samples that end up in the real products for the mere fact that they were the default, not because they suited the problem at hand.
This article details how to implement a Web Service, but with a better project structure, reduced coupling between components, and separation between interface definitions and their implementation. And last but not least, a new template is provided to fossilize these newly found principals.
For illustration purposes, the article is structured around a phantom Web Service built atop of WCF. The service exposes a collection of resources through REST, which in turn can be hosted in IIS or standalone. Also, a sample web client application is included, as well as unit test for the core logic.
The notion of separating software projects into layers has been around for a while, but still, there seems to be a lot of confusion on terminology and techniques. Particularly, such discussion(s) often intermix tier separation and software layers, hence an introductory article "Pragmatic Architecture: Layering" by Ted Neward is recommended.
Web Service -- The 'REST Technobabble'
Software development is filled with new technology and new terminology, often for the same or even older technology, but in any case, there is plenty of technobabble involved. And in the case of this article, the Web Service actually manages a collection of REST technobabble phrases. A client of this Web Service can request a list of [latest] technobabble phrases, add new ones, modify existing, etc. (i.e., CRUD support).
For starters, let's review the projects involved and the way in which they are organized in the Visual Studio solution. Next to this paragraph is a snapshot of Solution Explorer, which shows several solution folders and corresponding projects. The solution folders correspond to layers, which are described later.
The key points about solution folders and projects are:
- Solution folders are prefixed with a two digit number (e.g., 10, 20) for ordering purposes.
- Project compilation is (still) controlled by project dependencies settings.
- Project/layer dependencies are visually conveyed to the developer.
- Projects at the top depend on lower [layer] projects.
The diagram next to this paragraph shows the Web Service, its contract, hosting, and client(s) are allocated to different layers. Arrows on the diagram show compile time dependencies between the different layers.
- Data Layer -- abstraction of the persistent storage*
- Core -- the core logic of the implementation
- Web Services -- wrapper around the Core
- Host -- hosting of the Web Service (i.e., IIS hosting or standalone)
- Client -- the client application(s)
*Note: To limit the scope of this Web Service project, information is stored in memory and the corresponding logic is not factored out into a separate data layer.
Key points on the diagram for the layers and their dependencies:
- Compile time dependencies are shown as arrows.
- Higher layers depend on lower layers (and not vice versa).
- Client layer depends only on the contracts and not on the implementation layers.
The next diagram shows dependencies for the assemblies produced by the above projects. The diagram is produced by Visual Studio, and provides another confirmation that the layer dependencies have been observed. An interesting feature is that Visual Studio can also check these dependencies against the one specified in the layer diagram (above) and inform when an incorrect dependency has been added.
The key points on the diagram are:
- Client side assemblies depend only on the definition of the contracts
- Number of assemblies deployed on the client is smaller (hence smaller deployment size)
- Corrections in service implementation can be implemented without redeployment of the client assemblies
- Multiple clients (i.e. WebApp and WebMVC3) are build based only on the contract definition
Running the Sample
Now that you've read a lot of technobabble from the previous section, it may be interesting to see what the running Web Service looks like.
For demo purposes, I implemented the client to the Web Service as (another) web application that consumes and allows to manipulate the technobabble phrases (after all, technobabble is always evolving).
All projects have corresponding dependencies set up and hence the Build&Run of Client.WebApp project shall be sufficient. Otherwise, you can Build&Run the Host.WebApp project followed by (Build&Run) of the Client.WebApp project.
The most obvious difference when compared to the Visual Studio default WCF/REST template and the one shown here is the number of projects involved. But is it actually better?
Well, the answer is the venerable: "It depends", but here are some beneficial aspects of this approach:
- Separation of concerns -- Each project is focused on a smaller more specific task.
- Client side assemblies depend only on the definition of the contracts and hence no implementation assemblies need to be deployed to the client side.
- Number of assemblies deployed on a client is reduced (hence smaller deployment size).
- Corrections in service implementation can be implemented without redeployment of the client assemblies.
- Much easier implementation of unit test(s) for the functionality in the Core layer.
- Easier to address different API semantics (example: stateless aspect of REST vs. stateful usage on the internal API exposed by the Core layer).
- Web and Host projects can focus on their targets which are very technology specific and rapidly change over time.
All of the above seem more than fair benefit to have more granular projects.
As mentioned above, the Core layer can follow much simpler development practices. Because it has limited dependency on the deployment infrastructure, the unit test for it can be implemented much easier. Especially when compared to the system/integration level testing required when Client and Web Services are involved.
Additionally, the Web and Host projects can focus on their targets which are very technology specific and rapidly change over time. Today, the services are implemented with WCF and hosted in IIS through an ASP.NET project or a standalone executable; tomorrow it could be a Windows(R) Service or yet something else.
Points of Interest
Even in this simple example, the separation allows to address the difference in semantics much easier. For example, the service is exposed through REST and implemented though the .NET
WebGet attribute. This adds the restriction that only
string parameters will be parsed from the URI (behavior of the
WebGet implementation) and that consecutive identical calls to delete a resource is not an error condition (which it is in general procedural programming).
Integration with Visual Studio
And in conclusion to the best part: all of the above can be reasonably reused though a new Visual Studio template. To install the template, you can navigate to the Visual Studio Gallery, or even simpler, use Visual Studio to install it:
- Open the new project dialog in Visual Studio.
- Type in the search term: "structured".
- Select the "Structured WCF REST Service" item, and proceed with the wizard.
If everything works, you should see a dialog as the one shown below:
The source code can now be accessed at github:
Volumes of information regarding application/presentation split and the corresponding presentation/business logic/data access tiers are available -- in fact, too many to list here. Nevertheless, practical advise is rare. The following references were used for this article:
- Version 1.2: Addition of ASP.NET MVC3 client project
- Article update: Published template source
- Version 1.1: Console hosting application update
- Version 1.0: Initial release