The Dependency Injection (DI) pattern of software development offers many benefits in the area of separation of concerns. The loose-coupling nature of this pattern allows for truly atomic unit tests and (theoretically) more effective development.
While the DI pattern is well documented in web UI technologies that espouse separation of concerns (such as MVC), the use of this pattern in the less glamorous area of application integration using web services is a little leaner on the volume of documentation. Being that application integration apps such as WCF Services have a tendency to perform some elaborate transportation and transformation logic, having the benefits of the DI pattern greatly improves the effectiveness of the development of these applications.
So, in terms of WCF Services, how exactly do we achieve the DI pattern? Thanks to the lightweight Unity library, we can offer the following DI benefits for a WCF Service:
For this example, we will create a WCF Service project (hosted on IIS) which will contain the these two services, with their corresponding operations:
DateOperations.svc
[As an aside, the completed solution can be found in its entirety here for download! If you have a Subversion client, grab a Checkout from https://edg.sourcerepo.com/edg/Geekstentialism/Geekstentialism.SampleWCF/trunk/ ]
Defining the Application Architecture
Firing up Visual Studio 2010, we create a solution with the following projects:
Finally, following separation of concerns, the projects themselves need to reference each other in the following pattern:
So, now we've got our solution all setup with all the proper references to external libraries (Unity, Unity.Interception, and Moq) and each other. We can begin the fun part...coding!
The Foundation: Interfaces
I personally like starting from the ground up, so let's attack the Geekstentialism.SampleWCF.Common project first. First, we create an Interfaces folder. We're going to need to create the following interfaces in this folder (note, links follow you to the each file in source control):
Also, the service interfaces (aka the ones our actual WCF services will implement) will define the ServiceContract and OperationContract text decorations in preparation for WCF Service use.
The Heavy Lifting: Components
Following a familiar n-tiered architecture (and good separation of concerns), the actual implementation of the operations above will not live on the Service code itself. We have a Component layer which will facilitate this logic. Some circles call this the Business Object layer, but it serves the same purpose: do the heavy lifting behind the scenes! These objects will be created in the Geekstentialism.SampleWCF.Components class library project.
We will implement the following components:
The Integrators: Services
This is the layer where we get into Dependency Injection, the Geekstentialism.SampleWCF.Services project. If you think about our structure above, we will create a DateOperationsService that is dependent on the DateOperationsComponent. However, since one of the key tenets to DI is to program against interfaces, we are actually going to create a constructor for this class with one parameter, the IDateOperationsComponent interface. We will then create a NumericOperationsService with the same structure, except its constructor's one parameter is the INumericOperationsComponent interface.
Both services will obviously also implement their respective interfaces (IDateOperationsService and INumericOperationsService, respectively). So, how do we hook up the corresponding components' methods to these interfaces' methods? Quite simply, we define a private object that will hold the interfaces mentioned above and call the methods from those interfaces directly. For example, for DateOperationsService, we will create a private object called dateOperationsComponent, which is an IDateOperationsComponent type. In the constructor which takes this interface, we assign this private object's value to the interface coming in on the constructor. We will follow the same pattern for the NumericOperationsService.
For those who are new to Dependency Injection, take heed that we will put everything together when we get to the topmost layer, the web project. However, if you care for some light reading, here is quite possibly the easiest explanation for the DI concept and why we apply this pattern in software development.
The Sanity Checks: Unit Tests
Now, we get to perhaps the second most important thing to get right apart from the Web Project -- the test project. While I can imagine some groans coming from my fellow developers, allow me to offer my experiences with unit tests on a properly decoupled application such as the one we have just built. When properly constructed, your unit tests will save you an unbelievable amount of time, especially when you make changes to your software. Get into the habit of creating proper unit tests and configuring your projects to run them first. It can be an odious task, but it is worthwhile.
Now that I'm off my soap box, let's write up some unit tests for our decoupled components. We'll create the following folders: Services and Components.
In the Services folder, we will create the DateOperationsServiceTest and NumericOperationsServiceTest unit test classes.
In the Components folder, we will create the DateOperationsComponentTest and NumericOperationsComponentTest unit test classes.
Remember the reference to Moq we had created earlier in this Geekstentialism.SampleWCF.Tests project? We're going to put them to use, specifically in the Services tests. This is the beauty of DI and programming to interfaces -- when we create our unit tests for our service operations, we do not actually instantiate concrete DateOperationsComponent and NumericOperationsComponent classes. We instead mock up these components (using Moq) since these unit tests only care for the logic happening on the Service layer. So, we appropriately mock up our Components classes in the Services tests and write a few assertions. Since these services are so simple, we simply assert that the methods on the Component Layer were called once. Loosely coupled software ftw!
Finally, since the Components themselves aren't dependent on anything, writing Unit tests for these are fairly straightforward, testing the functionality requested above.
The Front-end: Web Project
So we have a very nice structure above, separating the concerns of the service and business logic. What you're most likely asking right now is, how the heck do these services get exposed? They are, after all, just simple class libraries, and we didn't create concrete .svc files on the web project (nor do we want to!). This is where Unity works its magic. The key to dependency injection is to let the DI container know what the default constructor for an interface is, and all this magic happens in the web.config in the Geekstentialism.SampleWCF.Web project.
Before we muck around the web.config, let's drop some prerequisites to get the web project. Let's create a new folder called Unity. We're going to create four supporting objects: UnityServiceHost, UnityServiceHostFactory, UnityServiceBehavior, and UnityInstanceProvider. Thanks to an example from our friends at Avington Solutions, we have this code readily available in the full example which you are free to use. In short, these classes will do the magic of using the Unity containers and activating the services we configure in web.config.
With these supporting objects in place, let's do some web.config hacking! The first thing we need to do is to define a config section for Unity, where we'll define the default constructs for our interfaces.
Next, let's modify our system.ServiceModel node. We want to use the aforementioned supporting Unity classes for service activation, so we won't have to maintain those pesky .svc files. This will be defined in the serviceHostingEnvironment node. We're going to create a serviceActivations node and then configure two services : ./DateOperations.svc, which will be activated using Geekstentialism.SampleWCF.Services.DateOperationsService, and ./NumericOperations.svc which will be activated using Geekstentialism.SampleWCF.Services.NumericOperationsService. You'll notice that we are also using our newly created UnityServiceHostFactory as the factory for both services.
Finally, we'll define the unity config section with the default concrete objects for IDateOperationsComponent and INumericOperationsComponent respectively. This is our web.config in its finished state.
Voila! With this architecture in place, we now have a file-less WCF Service Application with two services and proper Dependency Injection. We've also got some nifty unit classes in place that will quickly identify any logical issues for us should we change any layer of our WCF application.
When we invoke our operations using their WSDL's and soapUI as our primary testing tool, we can see they work beautifully.
The Wrap-up
Using Dependency Injection with WCF Services offers us the same benefits as it does for more glamorous architectures such as MVC. Using the DI techniques above, you can craft even more complex WCF Services -- perhaps end-to-end transport services -- and ensure that your software will be agile, well-tested, and elegant!
While the DI pattern is well documented in web UI technologies that espouse separation of concerns (such as MVC), the use of this pattern in the less glamorous area of application integration using web services is a little leaner on the volume of documentation. Being that application integration apps such as WCF Services have a tendency to perform some elaborate transportation and transformation logic, having the benefits of the DI pattern greatly improves the effectiveness of the development of these applications.
So, in terms of WCF Services, how exactly do we achieve the DI pattern? Thanks to the lightweight Unity library, we can offer the following DI benefits for a WCF Service:
- File-less activation of services (no more pesky .svc files to maintain)
- Loosely coupled development
- Rapid and agile development thanks to unit testing
For this example, we will create a WCF Service project (hosted on IIS) which will contain the these two services, with their corresponding operations:
DateOperations.svc
- DayOfYear [DateTime Input, Integer Output]: Returns the day of the year for a given date
- CalendarQuarter [DateTime Input, String Output]: Returns a fiscal quarter string (ex. "3Q12") based on calendar quarters
- CalculateSalesTax [Decimal and String Input, Decimal Output]: Returns the sales tax for a total value for a given state.
[As an aside, the completed solution can be found in its entirety here for download! If you have a Subversion client, grab a Checkout from https://edg.sourcerepo.com/edg/Geekstentialism/Geekstentialism.SampleWCF/trunk/ ]
Defining the Application Architecture
Firing up Visual Studio 2010, we create a solution with the following projects:
- Geekstentialism.SampleWCF.Web: Our WCF Service Application web project which will be hosted on IIS. Go ahead and remove the default .svc and interface files the template creates, we will have no use for them in this example.
- Geekstentialism.SampleWCF.Services: Class library which contains the concrete implementations of our services
- Geekstentialism.SampleWCF.Common: Class library which contains the interfaces implemented by our services
- Geekstentialism.SampleWCF.Components: Class library which contains operations specific to components. For example, a NumericOperationsComponent which handles the calculations for the NumericOperations service.
- Geekstentialism.SampleWCF.Tests: The Unit Test project
Finally, following separation of concerns, the projects themselves need to reference each other in the following pattern:
- Geekstentialism.SampleWCF.Web: References Geekstentialism.SampleWCF.Common and Geekstentialism.SampleWCF.Services
- Geekstentialism.SampleWCF.Services: References Geekstentialism.SampleWCF.Common and Geekstentialism.SampleWCF.Components
- Geekstentialism.SampleWCF.Components: References Geekstentialism.SampleWCF.Common
- Geekstentialism.SampleWCF.Tests: References all projects
So, now we've got our solution all setup with all the proper references to external libraries (Unity, Unity.Interception, and Moq) and each other. We can begin the fun part...coding!
The Foundation: Interfaces
I personally like starting from the ground up, so let's attack the Geekstentialism.SampleWCF.Common project first. First, we create an Interfaces folder. We're going to need to create the following interfaces in this folder (note, links follow you to the each file in source control):
- IDateOperationsComponent: The interface which is the basis of DateOperationsComponent, the heavy lifting arm of the DateOperationsService.
- INumericOperationsComponent: The interface which is the basis for NumericOperationsComponent, the heavy lifting arm of the NumericOperationsService.
- IDateOperationsService: The contract which the DateOperationsService will follow.
- INumericOperationsService: The contract which the NumericOperationsService will follow.
Also, the service interfaces (aka the ones our actual WCF services will implement) will define the ServiceContract and OperationContract text decorations in preparation for WCF Service use.
The Heavy Lifting: Components
Following a familiar n-tiered architecture (and good separation of concerns), the actual implementation of the operations above will not live on the Service code itself. We have a Component layer which will facilitate this logic. Some circles call this the Business Object layer, but it serves the same purpose: do the heavy lifting behind the scenes! These objects will be created in the Geekstentialism.SampleWCF.Components class library project.
We will implement the following components:
- DateOperationsComponent: Implements the IDateOperationsComponent above. The actual implementation for DayOfYear and CalendarQuarter will be implemented in this object.
- NumericOperationsComponent: Implements the INumericOperationsComponent above. Again, we will place the concrete implementation for CalculateSalesTax here.
The Integrators: Services
This is the layer where we get into Dependency Injection, the Geekstentialism.SampleWCF.Services project. If you think about our structure above, we will create a DateOperationsService that is dependent on the DateOperationsComponent. However, since one of the key tenets to DI is to program against interfaces, we are actually going to create a constructor for this class with one parameter, the IDateOperationsComponent interface. We will then create a NumericOperationsService with the same structure, except its constructor's one parameter is the INumericOperationsComponent interface.
Both services will obviously also implement their respective interfaces (IDateOperationsService and INumericOperationsService, respectively). So, how do we hook up the corresponding components' methods to these interfaces' methods? Quite simply, we define a private object that will hold the interfaces mentioned above and call the methods from those interfaces directly. For example, for DateOperationsService, we will create a private object called dateOperationsComponent, which is an IDateOperationsComponent type. In the constructor which takes this interface, we assign this private object's value to the interface coming in on the constructor. We will follow the same pattern for the NumericOperationsService.
For those who are new to Dependency Injection, take heed that we will put everything together when we get to the topmost layer, the web project. However, if you care for some light reading, here is quite possibly the easiest explanation for the DI concept and why we apply this pattern in software development.
The Sanity Checks: Unit Tests
Now, we get to perhaps the second most important thing to get right apart from the Web Project -- the test project. While I can imagine some groans coming from my fellow developers, allow me to offer my experiences with unit tests on a properly decoupled application such as the one we have just built. When properly constructed, your unit tests will save you an unbelievable amount of time, especially when you make changes to your software. Get into the habit of creating proper unit tests and configuring your projects to run them first. It can be an odious task, but it is worthwhile.
Now that I'm off my soap box, let's write up some unit tests for our decoupled components. We'll create the following folders: Services and Components.
In the Services folder, we will create the DateOperationsServiceTest and NumericOperationsServiceTest unit test classes.
In the Components folder, we will create the DateOperationsComponentTest and NumericOperationsComponentTest unit test classes.
Remember the reference to Moq we had created earlier in this Geekstentialism.SampleWCF.Tests project? We're going to put them to use, specifically in the Services tests. This is the beauty of DI and programming to interfaces -- when we create our unit tests for our service operations, we do not actually instantiate concrete DateOperationsComponent and NumericOperationsComponent classes. We instead mock up these components (using Moq) since these unit tests only care for the logic happening on the Service layer. So, we appropriately mock up our Components classes in the Services tests and write a few assertions. Since these services are so simple, we simply assert that the methods on the Component Layer were called once. Loosely coupled software ftw!
Finally, since the Components themselves aren't dependent on anything, writing Unit tests for these are fairly straightforward, testing the functionality requested above.
The Front-end: Web Project
So we have a very nice structure above, separating the concerns of the service and business logic. What you're most likely asking right now is, how the heck do these services get exposed? They are, after all, just simple class libraries, and we didn't create concrete .svc files on the web project (nor do we want to!). This is where Unity works its magic. The key to dependency injection is to let the DI container know what the default constructor for an interface is, and all this magic happens in the web.config in the Geekstentialism.SampleWCF.Web project.
Before we muck around the web.config, let's drop some prerequisites to get the web project. Let's create a new folder called Unity. We're going to create four supporting objects: UnityServiceHost, UnityServiceHostFactory, UnityServiceBehavior, and UnityInstanceProvider. Thanks to an example from our friends at Avington Solutions, we have this code readily available in the full example which you are free to use. In short, these classes will do the magic of using the Unity containers and activating the services we configure in web.config.
With these supporting objects in place, let's do some web.config hacking! The first thing we need to do is to define a config section for Unity, where we'll define the default constructs for our interfaces.
Next, let's modify our system.ServiceModel node. We want to use the aforementioned supporting Unity classes for service activation, so we won't have to maintain those pesky .svc files. This will be defined in the serviceHostingEnvironment node. We're going to create a serviceActivations node and then configure two services : ./DateOperations.svc, which will be activated using Geekstentialism.SampleWCF.Services.DateOperationsService, and ./NumericOperations.svc which will be activated using Geekstentialism.SampleWCF.Services.NumericOperationsService. You'll notice that we are also using our newly created UnityServiceHostFactory as the factory for both services.
Finally, we'll define the unity config section with the default concrete objects for IDateOperationsComponent and INumericOperationsComponent respectively. This is our web.config in its finished state.
Voila! With this architecture in place, we now have a file-less WCF Service Application with two services and proper Dependency Injection. We've also got some nifty unit classes in place that will quickly identify any logical issues for us should we change any layer of our WCF application.
When we invoke our operations using their WSDL's and soapUI as our primary testing tool, we can see they work beautifully.
The Wrap-up
Using Dependency Injection with WCF Services offers us the same benefits as it does for more glamorous architectures such as MVC. Using the DI techniques above, you can craft even more complex WCF Services -- perhaps end-to-end transport services -- and ensure that your software will be agile, well-tested, and elegant!
1 comment:
The links all prompt for a username and password. What username and password?
Post a Comment