Purpose
Estimated time to complete this lab: 25 minutes
A Composite Web Application Block service is a supporting class that provides functionality to other components (the components can be in the same module or different modules) in a loosely coupled way, such as services that provide authorization, logging, or hardware communication functionality. The software factory includes a set of basic services that you can use in your applications. You can also build your own services that provide infrastructure capabilities specific to your applications.
In this exercise, you will learn how to create and register a service to be consumable by the module, and that will be automatically injected using ObjectBuilder. In this case, you will be implementing a simple electronic funds transfer (EFT) processing service.
Preparation
Before proceeding with this lab, you must install and configure the prerequisite software. For more information, see Web Client Software Factory Hands-On Labs.
Open the solution for the previous lab (either the one that you created or the end solution for that lab.) If you use the provided end solution, you must enable the guidance package for that solution.
To enable the Web Client Development guidance package with the Guidance Package Manager
1. Using Visual Studio, open the solution.
2. On the Tools menu, click Guidance Package Manager.
3. In the Guidance Package Manager dialog box, click Enable / Disable Packages.
4. In the Enable and Disable Packages dialog box, select the Web Client Development check box.
5. Click OK.
Procedures
This lab includes the following tasks:
· Task 1: Create Application Classes Used by the Service
· Task 2: Create the Service Interface
· Task 3: Add a Service Implementation to Your Solution
· Task 4: Get Familiar with the Dependency Injection Pattern
· Task 5: Register the Service
· Task 6: Consume the Service
The next sections describe these tasks.
Task 1: Create Application Classes Used by the Service
In this task, you will create application-specific classes used by the sample service.
To create application-specific classes
1. In Solution Explorer, create a folder named BusinessEntities inside the EFT project.
2. Add a new code file named Transfer.cs to the BusinessEntities folder. To do this, right-click the BusinessEntities folder in Solution Explorer, point to Add, and then click Class.
3. Replace the contents of the Transfer.cs file with the following code.
using System;
namespace GlobalBank.EFT.BusinessEntities
{
public class Transfer
{
private string _sourceAccount;
private string _targetAccount;
private decimal _amount;
private string _status;
private Guid _id;
public Transfer()
{
}
public Transfer(string sourceAccount, string targetAccount, decimal amount, string status)
{
_sourceAccount = sourceAccount;
_targetAccount = targetAccount;
_amount = amount;
_status = status;
}
public Guid Id
{
get { return _id; }
set { _id = value; }
}
public string Status
{
get { return _status; }
set { _status = value; }
}
public decimal Amount
{
get { return _amount; }
set { _amount = value; }
}
public string TargetAccount
{
get { return _targetAccount; }
set { _targetAccount = value; }
}
public string SourceAccount
{
get { return _sourceAccount; }
set { _sourceAccount = value; }
}
}
}
Task 2: Create the Service Interface
In this task, you will define the interface for a service that performs an electronic funds transfer between two bank accounts.
To create the service interface
1. Create a folder named Interface in the EFT project. To do this, right-click the EFT project, point to Add, and then click New Folder.
2. Add a new interface named ITransferService.cs to the Interface folder. To do this, right-click the Interface folder, point to Add, and then click New Item. In the Add New Item dialog box, select the Interface template, enter ITransferService.cs as the name, and then click Add.
3. Copy and paste the following code to the file (this will be the service interface).
using GlobalBank.EFT.BusinessEntities;
using System;
namespace GlobalBank.EFT.Interface
{
public interface ITransferService
{
Transfer[] ProcessTransfers(Transfer[] transfers);
DateTime GetLastTransferDate();
}
}
Task 3: Add a Service Implementation to Your Solution
In this task, you will create an implementation of the electronic funds transfer (ETF) service.
To create an ETF service implementation
1. Add a new class named TransferService to the Services folder of the EFT project.
2. Add the following using statements to the top of the file.
using GlobalBank.EFT.Interface;
using GlobalBank.EFT.BusinessEntities;
3. Replace the class definition with the following code. This will be the concrete implementation of the service.
public class TransferService : ITransferService
{
private static DateTime _lastTransferDate = DateTime.MinValue;
public Transfer[] ProcessTransfers(Transfer[] transfers)
{
foreach (Transfer transfer in transfers)
{
transfer.Status = "Completed";
}
_lastTransferDate = DateTime.Now;
return transfers;
}
public DateTime GetLastTransferDate()
{
return _lastTransferDate;
}
}
Your solution should be similar to the solution shown in Figure 1.
Figure 1
Solution Explorer view showing the EFT service
Task 4: Get Familiar with the Dependency Injection Pattern
The Dependency Injection pattern promotes loose coupling between a class and the objects it depends on. With the Dependency Injection pattern, you do not instantiate the dependencies explicitly in your class. Instead, a class gets the objects it requires from an outside source. With the Web Client Software Factory, you express dependencies declaratively in your class definition. In the declaration, you specify an interface; you do not specify a concrete implementation. This means you can easily replace the implementation of an object that a class depends on, without changing the source code of the class. This is especially useful if you want to be able to test your classes in isolation. The Composite Web Application Block includes a dependency injection framework based on ObjectBuilder that you can use to implement the Dependency Injection pattern in your application; this framework is used frequently throughout the software factory.
For more information about the Dependency Injection pattern, see “Dependency Injection” in Web Client Software Factory Help.
Task 5: Register the Service
In this task, you will register the EFT service that you implemented in earlier tasks. You must register the service before another object can use dependency injection to obtain a reference to the service. You can register services either as module services or as global services. Module services are services that can be consumed only by the module that registers it. Global services are services that are available to all the modules in the solution. In this task, you will register the electronic funds transfer service as a module service.
To register module services, you implement the AddModuleServices method of the module initialization class of your business module.
A module initialization class is a class that implements the IModuleInitializer interface. This class contains initialization code that runs when the Composite Web Application Block loads the module. This interface defines two methods, Load and Configure. You implement these methods to perform module initialization tasks, such as registering services or adding site map nodes to the site map. For more information about module loading and the IModuleInitializer interface, see “Modules” in Web Client Software Factory Help.
To register the service
1. Open the EFT module initialization class (EFTModuleInitializer). This class is located in the EFTModuleInitializer.cs file located in the root of the EFT project.
2. Add the following using statements to the top of the file.
using GlobalBank.EFT.Interface;
using GlobalBank.EFT.Services;
3. Add the following code to the AddModuleServices method.
moduleServices.AddNew<TransferService, ITransferService>();
Note: moduleServices is a services collection. In this particular case, it is the collection of services of the EFT module. You use the AddNew method to have ObjectBuilder create a new instance of the service and add it to the services collection. By adding a service to the services collection of the EFT module, you register it as a module service, and it will always be available at run time to be injected by the ObjectBuilder in the current module.
The AddNew method allows you to specify the type that is used to register the service (this is the second generic parameter in the line of code you added in step 3). This is the type developers use to obtain a reference to the service when using the Dependency Injection pattern. By specifying the service’s interface as the registration type, you enable developers to write generic code that is not aware of the concrete service implementation being used. This is especially useful when testing your classes because you can easily replace dependencies with mock implementations to test your classes in isolation.
For more information about registering services, see “How to: Register and Use Services” in Web Client Software Factory Help.
Task 6: Consume the Service
In this task, you will use dependency injection to obtain a reference to the EFT service.
To consume the service
1. Open the EFT module controller class file (EFTController.cs).
2. Add the following using statements to the top of the file.
using Microsoft.Practices.ObjectBuilder;
using GlobalBank.EFT.Interface;
3. Add the following member variable declaration.
private ITransferService _transferService;
4. Add a second constructor that uses dependency injection to obtain a reference to an implementation of the ITransferService. Use the InjectionConstructor attribute to specify this as the constructor ObjectBuilder will use when it constructs the object.
[InjectionConstructor]
public EFTController
([ServiceDependency] ITransferService transferService)
{
_transferService = transferService;
}
5. Implement a method to retrieve the last transfer date. To do this, add the following virtual method to the controller class.
public virtual DateTime GetLastTransferDate()
{
return _transferService.GetLastTransferDate();
}
Notice that there is no reference to the concrete implementation of ITransferService. This is because you used the overloaded version of the AddNew<TService, TRegisterAs>() method in Task 4 that registers the service by an interface type. ObjectBuilder will automatically inject the registered implementation for that interface type when ObjectBuilder instantiates the controller (notice the ServiceDependency attribute applied to the parameter in the constructor). This would allow changing the implementation of the service with another class and keeping the source code changes to a minimum (only the registration would change).
Verification
In this section, you will create a unit test to validate that the controller successfully consumes the electronic funds transfer service.
Verification involves performing the following tasks:
· Task 1: Create a Mock Service
· Task 2: Add a Unit Test
The next sections describe these tasks.
Task 1: Create a Mock Service
In a unit test, mock objects can simulate the behavior of complex, real (non-mock) objects. Mock objects are useful when a real object is difficult (or impossible) to incorporate into a unit test and when you want to test a component in isolation. In this task, you will create a mock EFT service so you can test the EFTController class in isolation.
To create a mock service
1. Add a new class named MockTransferService to the Mocks folder of the EFT.Tests project.
2. Add the following using statements to the top of the MockTransferService.cs file.
using GlobalBank.EFT.Interface;
using GlobalBank.EFT.BusinessEntities;
3. Replace the class definition with the following code.
public class MockTransferService : ITransferService
{
public DateTime LastTransferDate = new DateTime(2000, 1, 1);
public DateTime GetLastTransferDate()
{
return LastTransferDate;
}
public Transfer[] ProcessTransfers(Transfer[] transfers)
{
return transfers;
}
}
Task 2: Add a Unit Test
In this task, you will add a unit test to validate that the EFTController successfully consumes the EFT service.
To add a unit test
1. Open the EFTModuleControllerFixture class file.
2. Add the following using statements to the top of the file.
using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.ObjectBuilder.WCSFExtensions;
using GlobalBank.EFT.Tests.Mocks;
using GlobalBank.EFT;
using GlobalBank.EFT.Interface;
3. Add the following test method.
[TestMethod]
public void GetLastTransferDateConsumesITransferService()
{
MockTransferService service = new MockTransferService();
EFTController controller = new EFTController(service);
DateTime transferDate = controller.GetLastTransferDate();
Assert.AreEqual<DateTime>(service.LastTransferDate, transferDate);
}
The test sets up an instance of the EFTController that uses the mock EFT service. It calls the GetLastTransferDate method of the controller, and then it asserts that the date returned is the last transfer date of the transfer service
4. Use Test Manager to run the test. To do this, perform the following steps:
a. In Solution Explorer, click EFT.Tests.
b. On the Test menu, click Start Selected Tests Project without Debugger (or press CTRL+SHIFT+X).
The results will display in the Test Results window.
Note: To see how to unit test a module initialization class to verify that it registers a service, see the class NavigationModuleInitializerTest in the Navigation.Tests project of the Module QuickStart.