WCF RIA Services Unity DomainServiceFactory

Note: This post is based on WCR RIA Services PDC beta and changes can be made in a future release. 

In this post I will show you how it’s possible to create your own DomainServiceFactory which has the responsibility to create a DomainService instance. I decided to use Unity as a Dependency Injection framework to create my DomainServices. Why do we even want to create a custom DomainServiceFactory, well, to avoid dependencies inside our DomainServices, for example here is a DomainService which has a dependency to a CustomerRepository:

 
    [EnableClientAccess()]
    public class CustomerService : DomainService
    {

        public CustomerPM GetCustomerByID(int customerID)
        {
            var customerRepository = new CustomerRepository();
            var customer = customerRepository.GetCustomerByID(customerID);

            return new CustomerPM()
                   {
                      CustomerID = customer.CustomerID,
                      FullName = customer.FirstName + " " + customer.LastName,
                      Age = customer.Age
                   };
        }
    }

 

The code above will break the Dependency Inversion Principle, High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. We can’t use the code above in a unit-test, because it will use the CustomerRepository, so in that case we are doing an integration test. Our DomainService is now tightly coupled with the CustomerRepository. So to remove the detail (CustomerRepository) and use an abstraction, we can use the following solution:

    [EnableClientAccess()]
    public class CustomerService : DomainService
    {
        private ICustomerRepository _customerRepository;

        public CustomerService(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        public CustomerPM GetCustomerByID(int customerID)
        {
            var customer = _customerRepository.GetCustomerByID(customerID);

            return new CustomerPM()
                   {
                       CustomerID = customer.CustomerID,
                       FullName = customer.FirstName + " " + customer.LastName,
                       Age = customer.Age
                   };
        }
    }

 

Now the detail is removed, and we work against an abstraction (ICustomerRepository). We can now easily use this DomainServices with different kind of CustomerRepository as long as they implements the ICustomerRepository. We can now create our a test stub for the CustomerRepository when we write our unit-test etc. The problem with the code above, is that WCF RIA Services will throw an exception when it will try to create an instance of the DomainService. It will by default use the default constructor. If we add a default constructor, there is no way for the WCF RIA Services to know that we need to pass in a ICustomerRepository, so our GetCustomerByID method will throw and null reference exception when we try to call the CustomerRepository’s GetCustomerByID method. To solve this we can create our own DomainServiceFactory, where we handle the creation of the DomainService.

To create a DomainServiceFactory we need to create a class that implements the IDomainServiceFactory interface, and implement two methods, CreateDomainService and ReleaseDomainService:

 public class MyDomainServiceFactory : IDomainServiceFactory
 {
        
        public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)
        {
            var service = Global.UnityContainer.Resolve(domainServiceType) as DomainService;
            service.Initialize(context);

            return service;
        }


        public void ReleaseDomainService(DomainService domainService)
        {
            domainService.Dispose();
        }
}


The CreateDomainSerivce method will be called when WCF RIA Services will create an instance of our DomainSerivce, and the ReleaseDomainService will be called when WCF RIA Services will release it. To make the factory work, we must call the Initialize method of the DomainService we have created before returning it. The code above will use Unity to create an instance of a DomainService and if they have any dependencies, Unity will inject them if they are registered to the UnityContainter.

To register our IDomainServiceFactory we use the DomainSerivce.Factory property, which is a static property, we can for example use it in Application_Start in global.asax to configure the use of our factory:

    public static UnityContainer UnityContainer = new UnityContainer();


protected void Application_Start(object sender, EventArgs e) { DomainService.Factory = new MyDomainServiceFactory();
UnityContainer.RegisterType<CustomerService>(); UnityContainer.RegisterType<ICustomerRepository, CustomerRepository>(); }


Note: For demonstartion purpose I simply add a static UnityContainer to the Global.asax file, and in the MyDomainServiceFactory I access the UtnityContainer by writing Global.UnityContainer.

I also register my DomainService and Repositories in Global.asax.

Now when WCF RIA Services wants to create a DomainService, it will use the MyDomainServiceFactory, which will use Unity to create an instance of the DomainService, and CustomerRepository will be injected to the CustomerService.

Something I want to see in the future, is that Microsoft makes sure we can create our own DomainService method Invoker, or at least add two public events, OnOperationExecuting and OnOperationExecuted, so we can simply add pre- and post conditions, or have more possibility to extend the WCF RIA Services.

If you want to know when I publish a new blog post, you can follow me on twitter: http://www.twitter.com/fredrikn

1 Comment

Comments have been disabled for this content.