Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / IIS

WCF by Example - Chapter VII - Decoupling of WCF Services from the ViewModel

5.00/5 (16 votes)
11 Oct 2011CPOL7 min read 69.5K  
Baseline WCF Distribution Layer - Decoupling of WCF Services and ViewModels.

Previous

Next

Chapter VIChapter VIII

The Series

WCF by example is a series of articles that describe how to design and develop a WPF client using WCF for communication and NHibernate for persistence purposes. The series introduction describes the scope of the articles, and discusses the architect solution at a high level.

Chapter Overview

In the previous chapter, we introduced a basic WPF client. Currently, the View and the Model are almost ready, but the ViewModel does not provide any mechanism for calling service methods. We previously discussed the need for decoupling the client from the WCF distribution layer. The goal is to provide a development environment for RAD that leverages business exploration without the overhead of deploying a full production infrastructure. We would like to provide a development environment where changes are inexpensive and deployments are easy. We don't want to install services in IIS, or maintain a SQL Server database; we are looking for an installation that comprises a bunch of files that can be deployed in a memory stick if needed. BAs, product owners, testers should be able to execute this application in an easy manner.

Therefore, we need to abstract the distribution layer so different implementations can be used in a transparent manner. In this chapter, we will describe the contract locator and how the client uses this mechanism to put in place a sort of pipeline pattern that provides the required functionality we are looking for.

The original implementation, although it resolved the coupling issue between the client and services, it imposed the overhead of maintaining a set of client classes for each service implementation. A ServiceAdapter based on generic classes with generic functions and anonymous methods provide a much better implementation where the client does not need to implement any additional classes to decouple the service calls. We also introduce in this article the CommandDispatcher which is required at a later stage when WCF services are introduced on the client side, see Chapter WCF by Example - Chapter XII - WCF Implementation for more details.

The source code for this chapter can be found at CodePlex change set 93405. The latest code for the eDirectory solution can be found at CodePlex.

Client Re-factor

For those that are familiar with the series and may be interested to know what the scope of the re-factor was. The following screen indicates which files were added, removed, and modified:

Image 3

The following actions were taken for the re-factor:

  • Get rid of the IClientServices in the WPF project
  • Get rid of the IContractLocator:
    • ServerContractLocator is gone -- Need to re-fator tests: CustomerServiceTests
    • Remove it from the ClientServiceLocator -- A ref to ICommandDispatcher is required
    • Remove ClientContractLocator
    • Remove IContractLocator
    • Remove CustomerServiceAdapter in the WPF project
    • Remove the ServiceAdapterBase class in the WPF project
  • Add eDirectory.Common.Message, ICommandDispatcher
  • Add CommandDispatcher to ClientServiceLocator
  • Create Server DirectCommandDispatcher class
  • Create generic ServiceAdapter class -- this version does not include the async internal dispatcher
  • Refactor tests

Command Dispatcher

The ICommandDispatcher interface provides a mechanism for clients to indicate which method and parameters are used when invoking a given service. The only requirement for the client is to know the contract interface, it does not require to know about the implementation. On the other hand, the responsibility of the ICommandDispatcher is to deal with the service implementation and pass the method results to the client. The interface is:

C#
public interface ICommandDispatcher
{
    TResult ExecuteCommand<TService, TResult>(Func<;TService, TResult> command)
        where TResult : IDtoResponseEnvelop
        where TService : class, IContract;
}

In this chapter, we will only discuss the DirectCommandDispather implementation that we use to connect the client directly to the service back-end without the need of WCF and deploying the application on IIS. In this mode, the application just runs on a single application domain. This is useful for testing and RAD purposes. The implementation is very simple:

C#
public class DirectCommandDispatcher
    : ICommandDispatcher
{
    #region Implementation of ICommandDispatcher<TService>

    public TResult ExecuteCommand<TService, TResult>(Func<TService, TResult> command)
        where TResult : IDtoResponseEnvelop
        where TService : class, IContract
    {
01      var service = GetService<TService>();
        return command.Invoke(service);
    }

    #endregion

02  private readonly IDictionary<Type, Type> _serviceMap = new Dictionary<Type, Type>
                            {
                                {typeof(ICustomerService), typeof(CustomerService)}
                            };

    private TService GetService<TService>() where TService : class, IContract
    {
        var type = typeof(TService);
        if (!_serviceMap.ContainsKey(type))
        {
            var msg = "Implementation for contract: {0} was " + 
                      "not defined in the dispatcher service map";
            msg = string.Format(msg, type.Name);
            throw new NotImplementedException(msg);
        }
03      return (TService)Activator.CreateInstance(_serviceMap[type]);
    }
}

The implementation is just a factory class (Line 01) that creates the service instance (Line 03) based on the TService that the client passes. If a new contract is added in the server side, the only aspect to remember is to add the service to the map in line 02.

In Chapter XII - WCF Implementation, we will discuss the WCF implementation of the CommandDispatcher. This is the production implementation and in a way simpler than the one we discussed above as it does not require any amendments when a contract is added to the solution.

Client Service Locator

For some client services, a single instance for the whole life of the client application is sufficient and recommended. I normally like to create a sort of service container where the code can easily fetch for this sort of resources without exposing the DI container. There are several ways to provide this functionality and people have different opinions. In this case, we use the locator pattern in conjunction with DI for dynamically resolving service implementations at run-time. For further information regarding DI, see Chapter X - Dependency Injection with Spring.Net.

The ClientServiceLocator implementation is straightforward; for the moment, we only expose the ICommandDispacher service but when we get to the end of the series, this locator will expose two other services.

C#
public class ClientServiceLocator
{
    static readonly Object LocatorLock = new object();
    private static ClientServiceLocator InternalInstance;

    private ClientServiceLocator() { }

    public static ClientServiceLocator Instance()
    {
        if (InternalInstance == null)
        {
            lock (LocatorLock)
            {
                // in case of a race scenario ... check again
                if (InternalInstance == null)
                {
                    InternalInstance = new ClientServiceLocator();
                }
            }
        }
        return InternalInstance;
    }

    public ICommandDispatcher CommandDispatcher { get; set; }
}

Service Adapter

The ServiceAdapter is being used by the ViewModels when they want to invoke service methods. This a generic class so the ViewModel when creating an instance also determines which service contract the ServiceAdapter will deal with, for example:

C#
01  var customerServiceAdapter = new ServiceAdapter<ICustomerService>();
    var dto = new CustomerDto
                            {
                                FirstName = "Joe",
                                LastName = "Bloggs",
                                Telephone = "9999-8888"
                            };

02  var customerInstance = 
        customerServiceAdapter.Execute(s => s.CreateNewCustomer(dto));

In line 01, a new instance is created for the ServiceAdapter passing the ICustomerService contract interface. This mechanism will help to invoke the service method in line 02. To execute the method, we just use the Execute method, this requires us to pass a function expression that takes an instance of the service (this is the responsibility of the CommandDispatcher) and executes one of its methods. The return value, always an instance from IDtoResponseEnvelop, is the result of the service method.

The way we have structured the ServiceAdapter and CommandDispatcher provides the developer a strong type mechanism for the ViewModels to invoke methods and pass input parameters. It is similar to the RepositoryLocator that we will see at a later stage within the series but the generic ServiceAdapter provides the additional functionality to deal with different service contracts. It is worth noting that the ServiceAdapter does not require a service implementation, and it is not its responsibility to create/maintain a service instance, the CommandDispatcher looks after this aspect. The main reason for this class is to manage the business warnings/messages in a generic manner. The implementation is as follows:

C#
public class ServiceAdapter<TService>
    where TService:class, IContract
{
    public TResponse Execute<TResponse>(Func<TService, TResponse> command)
        where TResponse : IDtoResponseEnvelop
    {
01          var dispatcher = ClientServiceLocator.Instance().CommandDispatcher;
02          var result = dispatcher.ExecuteCommand(command);
        if (result.Response.HasWarning)
        {
03              // TODO: Implement Business Warning processing -- See Chapter XIV

        }
        if (result.Response.HasException)
        {
04              // TODO: Implement Business Exception processing -- See Chapter XIV
        }
        return result;
    }
}

In line 01, we use the new ClientServiceLocator to fetch for the CommandDispatcher, then in line 02, the command is passed to the dispatcher; see how the ServiceAdapter does not have a clue which service implementation is being used.

This is not the definitive version of this class; in Chapter XIV - Validation and Exception Management, we will discuss the implementation of the business warning and exceptions within this class, lines 03 and 04. Also, in Chapter XII - WCF Implementation, a better mechanism for calling services in an async manner is covered.

Test Re-Factor

We already have a set of tests that execute our services from the server side. These tests have been re-factored to use the ServiceAdapter instead. In this manner, we can test the new infrastructure. I leave for the reader to inspect the code and see how these tests were implemented, they provide a comprehensive set of examples on how to call the ServiceAdapter.

Chapter Summary

In this charter, we have set up the baseline for our distribution layer in the client side. Our design provides the decoupling required between the ViewModel classes and the services that we mentioned at the start of the chapter. With a little change in our service tests, we have also demonstrated how easy it is to have the client invoke the services in the server side. This model is critical to provide a plug-gable architecture so we can deploy our application during business exploration without having to use WCF for leveraging the deployment process at this stage.

We have not discussed the WCF implementation; this aspect is covered in a later chapter in the series. However, as we will see, the WCF implementation is relatively straightforward once we have in place the pattern introduced in this chapter. See Chapter XII - WCF Implementation.

In the next chapter, we will see how commands are implemented in the front-end and how the ViewModel classes invoke the services using the ServiceAdapter mentioned in this chapter. We are very close to having a comprehensive infrastructure in both the client and server side to start deploying versions of our solution to our client.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)