Click here to Skip to main content
15,861,168 members
Articles / Web Development / IIS

WCF by Example - Chapter XII - WCF Implementation

Rate me:
Please Sign up or sign in to vote.
4.86/5 (20 votes)
18 Dec 2010CPOL15 min read 75.2K   36   18
In-proc WCF testing, dynamic client proxies, WCF Request context extension, and WCF client async commands.
PreviousNext
Chapter XIChapter XIII

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. The source code for the series is found at CodePlex.

Chapter overview

For the first time, besides the given name to the series, we will cover the WCF implementation. As indicated previously, we have provided a development environment for RAD practices where the business domain and UI are streamlined so feedback from the product owners is obtained in a quick fashion; we have discussed in previous chapters that development of the full back-end infrastructure is not required at this stage in the project. Development on the persistence or communication layers should be postponed until a stable domain is available. Although, it is a good practice to design services that will prove not to be problematic later when the WCF implementation takes place; the eDirectory solution, with the inclusion of DTOs, resolves the majority of those problems at the later stage.

It was originally envisaged that this section of the series will be covered in three different chapters, instead only one is to be produced. As a result of this decision, the chapter will be one of the largest so far in the series, we just hope this is not an issue for the readers. The main sections for the chapter are the following:

  • In-proc WCF testing
  • WCF services implementation and programmatic dynamic client proxies
  • WCF request context implementation
  • Client async commands

The section about in-proc WCF testing demonstrates how easy it is to execute the services using WCF; it is a good example of how to implement unit testing on WCF. Also, we will demonstrate how we can enhance our existing tests so they can also run using WCF. The purpose is to validate that the services running on WCF can send our communication objects on the "wire" and that the serialization is not failing. In fact, the design is so flexible that you could execute services using WCF with the in-memory or NHibernate mode. Isn't that nice?.

At a later stage in this chapter, we discuss what modifications are required to split our components between the client and the server. In summary, we will create a WCF Service Web Site project, discuss what changes are required in the client side, and which modifications are required at the client and the server in configuration terms. The section finishes describing how to run the server and the client running in different process for the first time in the series.

The chapter is then finished with the implementation of a customised WCF request context which handles the creation of service instances for each request processed in the server side.

In-proc WCF tests

We are going to see how it is relatively easy to create a test executing WCF services within one single process, which simplifies the creation and execution of unit tests. What we need is to execute the WCF server and client in the same process, which by the way, as many of you may know, is not the standard WCF configuration. As mentioned previously, the reason for having tests invoking WCF validates the serialization of the communication objects, which is probably one of the most important aspects when working with WCF.

As explained in previous chapters, in the eDirectory solution, we don't rely on the standard WCF infrastructure to communicate business warnings and exceptions; all communication objects are required to inherit from a base class that provides holders for warnings and exceptions. We should create tests for this communication infrastructure before we cover the business services. In the test project, we have declared a new service for this purpose, it exposes methods to ensure that we correctly handle business exceptions and warnings and application exceptions:

C#
namespace eDirectory.UnitTests.WCF
{
    [ServiceContract(Namespace = "http://eDirectory/testservices/")]
    public interface ITestService
        : IContract
    {
        [OperationContract]
        DtoResponse MethodThrowsBusinessException();

        [OperationContract]
        DtoResponse MethodReturnsBusinessWarning();

        [OperationContract]
        DtoResponse MethodReturnsApplicationException();
    }
}

The implementation of the test service is very straightforward, so please look at the source code for the complete implementation of the TestService class:

C#
namespace eDirectory.UnitTests.WCF
{
    public class TestService
            : ServiceBase, ITestService
    {
        #region Implementation of ITestService

        ...

        #endregion
    }
}

Our tests will require to create WCF Services and client channels, the WcfServiceHost provides a set of static helpers for this purpose. The StartService method is used for the creation of service instances; a net pipe endpoint is created using the interface type name:

C#
public class WcfServiceHost
{
    private static readonly IDictionary<Type, ServiceHost> 
            ServiceHosts = new Dictionary<Type, ServiceHost>();
    private static readonly IDictionary<Type, ChannelFactory> 
            ChannelFactories = new Dictionary<Type, ChannelFactory>();

    public static void StartService<TService, TInterface>() 
                  where TInterface : IContract
    {
        var serviceType = typeof(TService);
        var interfaceType = typeof(TInterface);
        if (ServiceHosts.ContainsKey(serviceType)) return;
01      var strUri = @"net.pipe://localhost/" + interfaceType.Name;
02      var instance = new ServiceHost(serviceType, new Uri(strUri));
03      instance.AddServiceEndpoint(interfaceType, new NetNamedPipeBinding(), strUri);
04      instance.Open();
05      ServiceHosts.Add(interfaceType, instance);
    }

    ...
}

In the above code snippet, in Line (01), we use the passed interface to create a unique URI. In Lines (02, 03 and 04), a NetNamedPipe endpoint is created. Line (05) adds the endpoint to a static service hashmap so we can get a reference to the instance at a later stage.

If we need to stop the above endpoint, the following method can be used:

C#
public class WcfServiceHost
{
    private static readonly IDictionary<Type, ServiceHost> 
      ServiceHosts = new Dictionary<Type, ServiceHost>();
    private static readonly IDictionary<Type, ChannelFactory> 
      ChannelFactories = new Dictionary<Type, ChannelFactory>();

    ...

    public static void StopService<TInterface>()
    {
        var type = typeof(TInterface);
        if (!ServiceHosts.ContainsKey(type)) return;            
        var instance = ServiceHosts[type];
        StopChannel<TInterface>();
        if (instance.State != CommunicationState.Closed) instance.Close();
        ServiceHosts.Remove(type);
    }

    ...
}

For the client side, two methods are provided, the InvokeService is the key method in this implementation. The combination of generics, service interfaces, and action delegates provides an easy way to execute services on WCF. Let's see how this is achieved:

C#
public class WcfServiceHost
{
    private static readonly IDictionary<Type, ServiceHost> 
            ServiceHosts = new Dictionary<Type, ServiceHost>();
    private static readonly IDictionary<Type, ChannelFactory> 
            ChannelFactories = new Dictionary<Type, ChannelFactory>();

    ...

    public static void InvokeService<T>(Action<T> action) where T : IContract
    {
01      var factory = GetFactory(action);
02      var client = factory.CreateChannel();
03      action.Invoke(client);              
    }

    public static ChannelFactory<T> GetFactory<T>(Action<T> action) 
           where T : IContract
    {
        var type = typeof (T);
04      if (ChannelFactories.ContainsKey(type))
             return ChannelFactories[type] as ChannelFactory<T>;
05      var netPipeService = new ServiceEndpoint(
            ContractDescription.GetContract(type),
            new NetNamedPipeBinding(),
            new EndpointAddress("net.pipe://localhost/" + type.Name));

06      var factory = new ChannelFactory<T>(netPipeService);
        ChannelFactories.Add(type, factory);
        return factory;
    }
}

For clarity purposes, an example of the execution of one of the tests may help to explain how it works:

C#
[TestClass]
public class InfrastructureTests
    :eDirectoryTestBase
{

    ...

    [TestMethod]
    public void ServiceReturnsWarning()
    {
10      WcfServiceHost.InvokeService<ITestService>(ServiceReturnsWarningCommand);
    }

    private void ServiceReturnsWarningCommand(ITestService service)
    {
11      var result = service.MethodReturnsBusinessWarning();
        Assert.IsTrue(result.Response.HasWarning, "A warning was expected");
        Assert.IsTrue(result.Response.BusinessWarnings.Count() == 1, 
                      "Only one warning was expected");
        Assert.IsTrue(result.Response.BusinessWarnings.First().Message.Equals(
                      "Warning was added"));
    }

    ...

}

Let's follow the test execution, it may prove to be easier:

  1. Line (10) invokes the WcfServiceHost.InvokeService indicating the action to execute and the service interface. This implies that the ServiceReturnsWarningCommand expects a reference to an instance that implements the service interface, this will be our WCF client proxy.
  2. InvokeService at Line (01) retrieves an instance of a WCF channel factory calling the GetFactory method.
  3. At Line (02), a client proxy is created using the factory.
  4. At Line (03), the passed delegate, the ServiceReturnsWarningCommand is called passing the client proxy.
  5. The proxy (service) is used to call the server method at Line (11).

This pattern where a combination of delegates and generics are used is constantly used in the eDirectory solution; it proves to be very powerful, but it may take a little bit of time for new comers to fully understand. If that is your case, you may want to spend a little bit of time debugging the tests until you are fully comfortable with this approach.

Line (05) needs to match to the server endpoint definition, this is why we use the interface type name in the URI definition.

We can now define a sort of template that we need to follow when writing WCF tests:

  1. Initialise the WCF server endpoint before the test starts
  2. At the end of the test, we close the server endpoint

So for InfrastructureTests, we can leverage the test framework capabilities to achieve the mentioned template:

C#
namespace eDirectory.UnitTests.WCF
{
    [TestClass]
    public class InfrastructureTests
        :eDirectoryTestBase
    {
        [TestInitialize]
        public override void TestsInitialize()
        {
            base.TestsInitialize();
            WcfServiceHost.StartService<TestService, ITestService>();
        }

        [TestCleanup]
        public override void TestCleanUp()
        {
            WcfServiceHost.StopService<ITestService>();
            base.TestCleanUp();
        }

        ...

    }
}

Before we finish this section, we are going to demonstrate how little effort is required to "upgrade" our tests so they execute using WCF:

C#
namespace eDirectory.UnitTests.WCF
{
    [TestClass]
    public class CustomerServiceWcfTests
01      : CustomerServiceTests
    {
        [TestInitialize]
02      public override void TestsInitialize()
        {
            base.TestsInitialize();
            WcfServiceHost.StartService<CustomerService, ICustomerService>();            
        }

03      [TestCleanup]
        public override void TestCleanUp()
        {
            WcfServiceHost.StopService<ICustomerService>();
            base.TestCleanUp();
        }

        [TestMethod]
04      public override void CreateCustomer()
        {
05          ExecuteBaseMethod(base.CreateCustomer);
        }

        [TestMethod]
        public override void FindAll()
        {
            ExecuteBaseMethod(base.FindAll);
        }

        [TestMethod]
        public override void CheckFindAllNotification()
        {
            ExecuteBaseMethod(base.CheckFindAllNotification);
        }

        [TestMethod]
        public override void UpdateCustomer()
        {
            ExecuteBaseMethod(base.UpdateCustomer);
        }

        private void ExecuteBaseMethod(Action action)
        {
06          WcfServiceHost.InvokeService<ICustomerService>
                (
                    service =>
                        {
                            this.Service = service;
                            action.Invoke();
                        }
                );
        }

    }
}

So that is all, we need to inherit from the original test class (line (01)) so we can initialise (line (02)) the endpoint as discussed. The test class provides a helper method named ExecuteBaseMethod which delegates to the already mentioned WcfServiceHost.InvokeService helper method. You also want to notice that we have changed the original class' methods to be declared virtual so they can be overridden on the WCF test implementation. Line (05) demonstrates how we can leverage our tests reusing the logic in the original test class. Not too bad.

WCF services implementation

It is worth noting that in the previous section, we discussed how to test our services on WCF without having to implement a WCF Server project or doing any changes on the client side; this approach permits the upfront testing of our services, postponing the full implementation for a later stage.

But at some stage, we will hit the wall and we will have to provide a server using WCF for our clients. This section discusses what is required to build a WCF web site exposing the server methods. It also discusses which changes are required on the client side, so WCF proxies are automatically generated without the use of a Web reference and Visual Studio generated proxies. In the final stage, we will briefly cover the server and client configuration settings. Before we continue, it is important to clarify some points:

  • The client has a reference to the the eDirectory.Common assembly
  • We don't use VS generated proxies on the client side, instead we create our WCF proxies programmatically
  • We will declare the methods on the server side, so for each request, a WCF instance is created; that is, we use PerCall methods

The purpose is to have two applications, the Client and a WCF Server running as a web server. The client is relatively simple:

Image 3

The server is where most components are found:

Image 4

We need to declare a new project; this is going to be a WCF Web Site project that eventually will be deployed on IIS. The implementation is relatively easy:

  • Each server service requires an SVC file
  • In the code-behind of the service, we indicate that the class inherits from the service class in the eDirectory.Domain assembly
  • Each server service is configured to invoke a factory helper class: ServiceFactory

And that is all, this is going to be a project with relatively little code, it is more about configuration which is probably the way it is supposed to be. The most important aspect is ServiceFactory, its main responsibility is to ensure the start-up of any infrastructure component like the Dependency Injection container. The implementation is as follows:

C#
namespace eDirectory.WcfService
{
    public class ServiceFactory : ServiceHostFactory
    {
        static readonly Object ServiceLock = new object();
        static bool IsInitialised;

        protected override ServiceHost CreateServiceHost(
                           Type serviceType, Uri[] baseAddresses)
        {
01          if (!IsInitialised) InitialiseService();
            return base.CreateServiceHost(serviceType, baseAddresses);
        }

        private void InitialiseService()
        {
            lock (ServiceLock)
            {
                // check again ... cover for a race scenario
                if (IsInitialised) return;
                InitialiseDependecy();
                IsInitialised = true;
            }
        }

        private void InitialiseDependecy()
        {
            string spring = @"file://" + HttpRuntime.AppDomainAppPath + 
              ConfigurationManager.AppSettings.Get("SpringConfigFile");
            DiContext.AppContext = new XmlApplicationContext(spring);
        }
    }
}

So at Line (01), when the service host is about to be created, the InitialiseService method is called which creates the Spring.Net container. There is not much more story in this project, the service classes are linked to this factory class using the service declaration statement:

ASP.NET
<%@ ServiceHost Language="C#" 
                Debug="true" 
                Service="eDirectory.WcfService.CustomerWcfService" 
                CodeBehind="CustomerWcfService.svc.cs" 
                Factory="eDirectory.WcfService.ServiceFactory" %>

And the code-behind could not be simpler:

C#
namespace eDirectory.WcfService
{    
    public class CustomerWcfService 
        : CustomerService
    {
    }
}

The last aspect is the WCF configuration settings: as with any other WCF solution, there is a little bit of effort in the setting of the configuration files. For the server, we have:

XML
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <!-- Use the following configuration file to execute the client with memory entities-->
01  <add key="SpringConfigFile" value="ServerInMemoryConfiguration.xml"/>
    <!--<add key="SpringConfigFile" value="NhClientConfiguration.xml"/>-->
  </appSettings>
  
  <system.web>
    ...
  </system.web>

  <system.serviceModel>
    <services>
02    <service name="eDirectory.WcfService.CustomerWcfService" 
             behaviorConfiguration="eDirectory.WcfServiceBehaviour">
        <endpoint address="CustomerServices" binding="basicHttpBinding" 
             bindingConfiguration="eDirectoryBasicHttpEndpointBinding" 
             contract="eDirectory.Common.ServiceContract.ICustomerService" />         
      </service>
    </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="eDirectory.WcfServiceBehaviour">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding name="eDirectoryBasicHttpEndpointBinding">
          <!--<security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"/>
          </security>-->
        </binding>
      </basicHttpBinding>
    </bindings>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
        </modules>
    </system.webServer>
</configuration>

There is a little noise in the above configuration file but it is not so bad. At Line(01), we indicate that we want to use the in-memory repositories in the server side instead of the NHibernate ones. Line (02) declares the server endpoint for the Customer services; in this example, basicHttp is used, but you could use anything else you want. The client also needs to be modified:

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
01  <add key="SpringConfigFile" value="file://WcfConfiguration.xml" />
  </appSettings>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="eDirectoryBasicHttpBinding" />
      </basicHttpBinding>
    </bindings>
    <client>
02    <endpoint address="http://localhost:40003/CustomerWcfService.svc/CustomerServices"
          binding="basicHttpBinding"
          contract="eDirectory.Common.ServiceContract.ICustomerService" 
          name="BasicHttpBinding_ICustomerService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>    
  </system.serviceModel>
</configuration>

At Line (02), we declare the endpoint address that is defined by default on the eDirectory.WcfService web project; this is one value that you will need to change when the server components are deployed to a proper IIS environment. Line (01) indicates that the client is running in WCF mode; we need to have a quick look at this implementation as this is the production one:

XML
<?xml version="1.0" encoding="utf-8" ?>
<!--
  WCF Configuration
  =================
-->
  <objects xmlns="http://www.springframework.net">

    <!-- CLIENT SERVICE LOCATOR -->
    <object 
            id="ClientServiceLocatorRef" 
            type="eDirectory.WPF.Services.ClientServiceLocator, eDirectory.WPF"  
            factory-method="Instance" 
            singleton="true">
      
      <property name="ContractLocator" ref="ClientContractLocatorRef" />
    </object>
    
    <!-- Client Contract Locator -->
    <object 
            id="ClientContractLocatorRef" 
01          type="eDirectory.WPF.Services.ClientContractLocator, eDirectory.WPF">
      
      <property name="NextAdapterLocator" ref="ContractLocatorRef" />
    </object>
    
    <!-- Next Adapter Locator -->
    <object
            id="ContractLocatorRef"
02          type="eDirectory.WPF.Services.Wcf.WcfContractLocator, eDirectory.WPF" />

  </objects>

This is probably a small and tidy Spring.Net configuration file when we compare it to the NHibernate or the in-memory ones; the good news is that this is the production version. In this implementation, we don't require any server assembly deployed on the client side any longer. At Line (02) is indicated that WcfContractLocator is used in this application mode. This class has not been implemented yet, and is the key for calling the WCF services. The client does not rely on WCF proxies auto generated by Visual Studio from a web reference; in fact, the client does not have such a reference at all. For some people, that could be surprising. Instead, we build the proxies dynamically; the only code required is in a base class named WcfAdapterBase:

C#
namespace eDirectory.WPF.Services.Wcf
{
    public class WcfAdapterBase<TContract> where TContract: class, IContract
    {
01      private class WcfProxy<TService>:
            ClientBase<TService> where TService : class, IContract
        {
            public TService WcfChannel
            {
                get
                {
02                  return this.Channel;
                }
            }
        }

03      protected TResult ExecuteCommand<TResult>(Func<TContract, TResult> command)
            where TResult : IDtoResponseEnvelop
        {
04          var proxy = new WcfProxy<TContract>();     
       
            try
            {
05              var result = command.Invoke(proxy.WcfChannel);
                proxy.Close();
                return result;
            }
            catch (Exception)
            {
                proxy.Abort();
                throw;
            }
        }
    }
}

This is another implementation where an Execute method is exposed. The signature of the method at this stage should be familiar, so we will not discuss it. The most important aspect here is Line (04), where a client proxy is generated using the generic private WcfProxy class. At Line (05), we invoke the command delegate passing a reference to the private Channel of the WcfProxy instance, which is the main reason for the WcfProxy class to be created.

For each service, we need to create a class that inherits from this class and implements the contract interface; for our client services, we have:

C#
namespace eDirectory.WPF.Services.Wcf
{
    public class CustomerServiceProxy
        :WcfAdapterBase<ICustomerService>, ICustomerService
    {
        #region Implementation of ICustomerService

        public CustomerDto CreateNewCustomer(CustomerDto customer)
        {
            return ExecuteCommand(proxy => proxy.CreateNewCustomer(customer));
        }

        public CustomerDto GetById(long id)
        {
            return ExecuteCommand(proxy => proxy.GetById(id));
        }

        public CustomerDto UpdateCustomer(CustomerDto customer)
        {
            return ExecuteCommand(proxy => proxy.UpdateCustomer(customer));
        }

        public CustomerDtos FindAll()
        {
            return ExecuteCommand(proxy => proxy.FindAll());
        }

        #endregion
    }
}

There is not so much going on in the above code. As it can be seen, the only purpose for the CustomerServiceProxy class is to delegate the execution to the ExecuteCommand method. The last piece of code is the WcfContractLocator, which is also straightforward:

C#
namespace eDirectory.WPF.Services.Wcf
{
    public class WcfContractLocator
        :IContractLocator
    {
        private ICustomerService CustomerServiceProxyInstance;

        public ICustomerService CustomerServices
        {
            get 
            {
                if (CustomerServiceProxyInstance != null)
                    return CustomerServiceProxyInstance;
                CustomerServiceProxyInstance = new CustomerServiceProxy();
                return CustomerServiceProxyInstance;
            }
        }
    }
}

At this stage, we could try to execute the client against the server. Check the configuration for the client so it is set to use the WCF mode. Set eDirectory.WcfService as the "start-up" project and press Shift+F5, then change the eDirectory.WPF client to be the "start-up" project and press F5. If the client works, and hopefully that is the case, it is doing so using WCF. That is pretty much your application executing on production mode. Not too bad.

Request implementation

At the beginning of the series, we discussed the need for a Global and Request context at the server side; most of our services are global, but when there is a need to store state for each request, we are dealing with a service that needs to be handled by the Request context. What it needs to take place is that each time a request is processed on the server side, any service intended to be used on the Request context needs to be created. WCF extensibility provides an excellent framework for enhancements of this sort; in our case, we will implement our own instance context extension. The following components are required when implementing this type of solution:

  • Implementation of IExtension; in our case, we'll call it: InstanceCreationExtension
  • Implementation of IInstanceContextInitializer; we'll name this one: InstanceCreationInitializer
  • Create an attribute implementing IContractBehavior; in our case, the attribute is called InstanceCreationAttribute

In terms of responsibility:

  • InstanceCreationExtension is the key component as it holds an instance of the services that need to be created for the request. In our case, it does create a BusinessNotifier instance.
  • InstanceCreationInitializer is responsible for declaring which extensions need to be added to the instance context when a request is processed on the server side.
  • InstanceCreationAttribute is the "glue" between our service implementations and our InstanceCreationInitializer.

Let us see the implementations. The extension is simple, besides of the constructor; the implementation subscribes to InstanceContext.Closed so some basic cleansing can be done when the request finishes:

C#
namespace eDirectory.Domain.AppServices.WcfRequestContext
{
    public class InstanceCreationExtension : IExtension<InstanceContext>
    {
        public DateTime InstanceCreated { get; private set; }
        public BusinessNotifier Notifier { get; private set; }

        public InstanceCreationExtension(DateTime instanceCreated)
        {
            InstanceCreated = instanceCreated;
            Notifier = new BusinessNotifier();
        }

        #region IExtension<InstanceContext> Members

        public void Attach(InstanceContext owner)
        {
            // Make sure we detach when the owner is closed
            owner.Closed += (sender, args) => Detach((InstanceContext)sender);
        }

        public void Detach(InstanceContext owner)
        {
            Notifier = null;
        }

        #endregion
    }
}

There is not too much to say about the InstanceCreationInitializer implementation:

C#
namespace eDirectory.Domain.AppServices.WcfRequestContext
{
    public class InstanceCreationInitializer : IInstanceContextInitializer
    {
        #region IInstanceContextInitializer Members
        
        public void Initialize(InstanceContext instanceContext, Message message)
        {
            // Add extension which contains the new instance creation index
            instanceContext.Extensions.Add(new InstanceCreationExtension(DateTime.Now));
        }
        
        #endregion
    }
}

Then the attribute class is also simple:

C#
namespace eDirectory.Domain.AppServices.WcfRequestContext
{
    public class InstanceCreationAttribute : Attribute, IContractBehavior
    {
        #region IContractBehavior Members

        public void AddBindingParameters(ContractDescription contractDescription, 
               ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, 
               ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, 
               ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            dispatchRuntime.InstanceContextInitializers.Add(
                            new InstanceCreationInitializer());
        }

        public void Validate(ContractDescription contractDescription, 
                             ServiceEndpoint endpoint)
        {
        }

        #endregion
    }
}

We also need to define a new implementation of IRequestContext so our business code can resolve the service for the given request. It is worth noting that this should only be used when running WCF services, otherwise you may find some issues:

C#
namespace eDirectory.Domain.AppServices.WcfRequestContext
{
    public class RequestContext
        : IRequestContext
    {
        public IBusinessNotifier Notifier
        {
            get
            {
                InstanceContext ic = OperationContext.Current.InstanceContext;
                InstanceCreationExtension extension = 
                     ic.Extensions.Find<InstanceCreationExtension>();
                return extension.Notifier;
            }
        }
    }
}

The last aspect is to modify our services so we indicate that the customised extension needs to be used:

C#
namespace eDirectory.Domain.Services
{
    [ServiceBehavior(InstanceContextMode = 
                     InstanceContextMode.PerCall)]
    [InstanceCreation]
    public class CustomerService
        :ServiceBase, ICustomerService
    {
        ...
    }
}

Now when a WCF client calls any customer service method, the customised extension creates a new BusinessNotifier instance so we can store state at request level only, isolating requests from each other. You may find this pattern very useful for security, auditing, or other tasks that need to be invoked at the start of each request.

Client Command Dispatcher - Async commands

There is one client aspect that may become more obvious once we start dealing with WCF. When the client executes a service proxy, it is doing so using the UI thread, something that is not a really good idea because it freezes the UI, and if the request takes a few seconds, the user may not be a happy one for too long. As a result, a re-factor of how the services are executed is needed. The ServiceAdapterBase class is a good candidate for adding the new code:

C#
namespace eDirectory.WPF.Services
{
    abstract class ServiceAdapterBase<TService> where TService: IContract
    {
        protected TService Service;

        protected ServiceAdapterBase(TService service)
        {
            Service = service;
        }              
        
        public TResult ExecuteCommand<TResult>(Func<TResult> command) 
               where TResult : IDtoResponseEnvelop
        {
            try
            {
01              Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
                TResult result = DispatchCommand(command);
                ...
                return result;
            }
            finally
            {
02              Mouse.OverrideCursor = null;
            }
        }

        private static TResult DispatchCommand<TResult>(Func<TResult> command)
        {
03          var asynchResult = command.BeginInvoke(null, null);
            while (!asynchResult.IsCompleted)
            {
04              Application.DoEvents();
                Thread.CurrentThread.Join(50);
            }
            return command.EndInvoke(asynchResult);
        }
    }
}

After the re-factor, we can see that two new things are taking place: the mouse pointer changes when a method is executed and the command is executed in an asynchronous manner. The pointer is nicely handled in Lines (01 and 02). The new DispatchCommand method executes the command and waits until it finishes, Line (04) being an ugly solution, it does the trick. (Can anyone advise a better approach?)

In the WPF classes, when this new behavior is applied, a new problem arises; when an action is executed, there is nothing stopping the user from clicking on something else; this might not be the intended behavior, so we need to handle some sort of state and then change the UI controls accordingly. For this purpose, a new field is added to the CustomerModel named IsEnabled. If this field is false (the Save button changes this state), then the "New Customer" groupbox and the "Refresh" button are disabled. We use XAML bindings instead of any code-behind; code-behind on the View must be always the last resource:

XML
<Window x:Class="eDirectory.WPF.Customer.View.CustomerView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:tk="http://schemas.microsoft.com/wpf/2008/toolkit"        
        Title="Customer View" Height="400" 
        Width="400" WindowStartupLocation="CenterScreen">
    
    ...
    <GroupBox Header="New Customer" Margin="5" 
      Padding="5" Grid.Row="0" 
      IsEnabled="{Binding Path=Model.IsEnabled}">
    ...
    <Button Grid.Row="1" Padding="5" 
      Margin="5" Command="{Binding RefreshCommand}" 
      IsEnabled="{Binding Path=Model.IsEnabled}">Refresh</Button>
    ...

Chapter summary

This chapter sets a major milestone in the series. Besides some minor aspects, we have covered the bulk of the components that a standard enterprise application requires. The series does not intent to be the best example for a WPF solution, nor the best example for an NHibernate integration; however, it demonstrates how three main enterprise frameworks can be integrated following best practices for RAD, TDD, and DDD.

In the next chapter, we will re-factor the business domain so a parent-child relationship is created; this implies a more complex UI, a new service, and a few changes in the domain.

We would appreciate feedback where we should conduct the series in the next future; we could cover aspects like validation, implementation of business warnings, and exceptions on the client side, maybe client report services using DTOs. But all those may not be that relevant for most people, maybe, instead, we could look into a Silverlight client.

License

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


Written By
Software Developer (Senior)
Ireland Ireland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Assil19-Aug-14 5:55
professionalAssil19-Aug-14 5:55 
GeneralMy vote of 5 Pin
Mahsa Hassankashi18-Aug-14 2:02
Mahsa Hassankashi18-Aug-14 2:02 
QuestionGreat Article! the series is awesome! i have a question Pin
iProg726-Aug-13 2:23
iProg726-Aug-13 2:23 
AnswerRe: Great Article! the series is awesome! i have a question Pin
Enrique Albert26-Aug-13 3:00
Enrique Albert26-Aug-13 3:00 
QuestionGreat Article! But how do you run the WCF test against the WCFHost generated proxy Pin
mwflem400631-May-13 9:54
mwflem400631-May-13 9:54 
AnswerRe: Great Article! But how do you run the WCF test against the WCFHost generated proxy Pin
Enrique Albert31-May-13 14:46
Enrique Albert31-May-13 14:46 
GeneralMy vote of 5 Pin
Rupesh Kumar Tiwari11-Oct-11 16:45
Rupesh Kumar Tiwari11-Oct-11 16:45 
GeneralMy vote of 5 Pin
prasad0222-Dec-10 3:47
prasad0222-Dec-10 3:47 
GeneralYou deserve a medal Pin
Chris Maunder13-Dec-10 2:45
cofounderChris Maunder13-Dec-10 2:45 
GeneralRe: You deserve a medal Pin
Enrique Albert13-Dec-10 3:01
Enrique Albert13-Dec-10 3:01 
GeneralPlease continue your series Pin
rittersh10-Dec-10 6:05
rittersh10-Dec-10 6:05 
GeneralRe: Please continue your series Pin
Enrique Albert10-Dec-10 21:45
Enrique Albert10-Dec-10 21:45 
GeneralRe: Please continue your series Pin
rittersh11-Dec-10 11:28
rittersh11-Dec-10 11:28 
GeneralRe: Please continue your series Pin
Enrique Albert16-Dec-10 2:55
Enrique Albert16-Dec-10 2:55 
GeneralRe: Please continue your series Pin
Enrique Albert10-Dec-10 21:46
Enrique Albert10-Dec-10 21:46 
GeneralRe: Please continue your series Pin
rittersh11-Dec-10 10:22
rittersh11-Dec-10 10:22 
GeneralRe: Please continue your series Pin
Enrique Albert22-Dec-10 21:48
Enrique Albert22-Dec-10 21:48 
GeneralRe: Please continue your series Pin
Enrique Albert2-Jan-11 12:49
Enrique Albert2-Jan-11 12:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.