Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / WPF

WCF in a stateful application (WPF/Silverlight)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
9 Apr 2013CPOL4 min read 27.4K   723   27   2
Handling the Faulted state and Closure of a WCF service when being used in a stateful application.

Introduction 

This article looks into a possible solution for handling the Faulted state and Closure of a WCF service when being used in a stateful application. 

The solution uses a Dynamic Proxy approach to handle the issue without breaking the original service contract. This enables a ViewModel to be dependent on the service interface without knowing it is actually using WCF.

Background

Consider a ViewModel which has the WCF service injected into it. There are a number of gotcha’s:

  1. How do we deal with the service when it becomes faulted, and the user is still using the window? 
  2. How do we ensure the service is cleaned up correctly? 
  3. How do we do the above two, whist working with the service interfaces? (Not knowing it’s actually a WCF service.) 

To expand on Point 3, it wants to make use of the interface which the service exposes (either a generated file or from a shared DLL) and it also wants to provide ease of unit testing (some mocking frameworks will not work with concrete classes).  

This post explores a solution using Dynamic Proxies. (Please provide any feedback if you know of another way.)

Side note:

Some IoC containers such as Castle Windsor, has a facility for all of this. Check out what your container does first. If it does not support handling of the WCF client channel, then this solution should work for you.

Side Side note:

Silverlight forces the user to implement the interface with async methods (there are some work a rounds, this solution can be used with them as well). This article will concentrate on WPF,  with a Silverlight version is contained in example solution. 

How to Use  

If you want to jump into using this here is what you will need to do:

  1. Add a reference to Castle.Core
  2. Download the WcfChannelProxy.zip project, and copy both of the files into your project
  3. In the application when you create your view, create the required service dependency (either directly via the WcfClientFactory or using an IoC Container) and inject the instance into your ViewModel.
C#
_service1 = new WcfProxy.WcfClientFactory().CreateClient<IService1>();
MainViewModel vm = new MainViewModel(_service1);
MainWindow window = new MainWindow(vm); 

To dispose of the service, that is simple too:

C#
//make sure we dispose of our channel, this would normally be
//taken care of by an IoC container
((IDisposable) _service1).Dispose(); 

The rest of this article discusses how the solution works and supplies a little more context.

VS Sample Sln Overview

A sample VS Sln has been provided to demonstrate the use of the solution and also highlight where constraints are applied. The solution is made of five projects, as follows:

Image 1

  • WCF host – web application, which hosts the WCF services (this is a file new WCF service project, with the addition of a client policy to allow the Silverlight client access)
  • WPF client – a simple WPF client 
  • Sl client – simple Silverlight client, using version 5
  • Sl host – web application which hosts the Silverlight XAP proj
  • Test – tests the interceptor of the dynamic project.

Both client solutions make use of the Dynamic Proxy (Wcf Proxy), to handle calling the web services. They both use the generated service reference, however the solution will also work with a shared DLL approach (where a seperate DLL contains the service interfaces and DTO's).

Overview of the Solution

The solution uses Castle’s Dynamic Proxy (WcfProxy) to provide the implementation of the service interface and shield the ViewModel from the channel maintenance.

Image 2

The Service

The aim is for the client to inject the interface of the services so the ViewModel will only to know of their operations. Here is the sample Service:

C#
[ServiceContract]
public interface IService1
{ 
    [OperationContract] 
    string GetData(int value); 
    
    [OperationContract]
    CompositeType GetDataUsingDataContract(CompositeType composite);
}  

There is no Close, Abort, or Dispose methods. Close and Abort can be made available to the client via generating a ServiceClient class (which is not an interface, harder to mock and test with) or by using the Channel directly (however, the consuming class would know of WCF directly).

The ViewModel

What the ViewModel depends on is key; the dependency interfaces will define the operations available to a ViewModel. Given we have Service1 (defined above) being injected to the ViewModel, this will mean the ViewModel cannot regulate the channel.

Below is the ViewModel, which is dependent on Service1, via constructor injection.

C#
public class MainViewModel : INotifyPropertyChanged
{ 
    private readonly IService1 _service1;
    private string _result;
 
    public MainViewModel(IService1 service1)
    {
        _service1 = service1;
        GetDataCmd = new DelegateCommand<object>(GetData);
        PropertyChanged += delegate { };
    }
 
    public string Result
    {
        get { return _result; }
        set
        { 
            _result = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Result"));
        }
    }
 
    public ICommand GetDataCmd { get; private set; }
 
    private void GetData(object o)
    {
        Result = _service1.GetData(123);
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
} 

The Proxy and Channel Factory Manager

The use of a, slightly modified, ChannelFactoryManager class. This is used to create and maintain Channel Factories and create new instances of Channels.

The solution constructs a Dynamic Proxy which implements the service interface, in this case IService1. The proxy instance has a WCF channel for the Service, which it maintains. When the channel becomes faulted, the proxy will clean up the faulted channel and request a new channel from the ChannelFactoryManager.

C#
/// <summary>
/// Provides a way to create a WCF proxy which will regulate its own channel
/// </summary>
/// <remarks>
/// if you are using Windsor, you could easily create a facility around this</remarks>
public class WcfClientFactory
{
    private static readonly ProxyGenerator Generator = new ProxyGenerator();
    private readonly IChannelFactoryManager _manager = new ChannelFactoryManager();
 
    public T CreateClient<T>() where T : class
    {
        var service = _manager.CreateChannel<T>();
        var proxy = Generator.CreateInterfaceProxyWithTargetInterface(typeof(T), 
            new[] { typeof(IDisposable) }, service, new WcfClientInterceptor<T>(service));
        return (T)proxy; 
    } 
} 
/// <summary>
/// Interceptor which manages the WCF channel, trying to ensure the channel is not faulted. this
/// is intended only to be used in state full applications. (for stateless then look at using the WCF Facility) 
/// </summary>
/// <typeparam name="TService">the channel interface</typeparam>
public class WcfClientInterceptor<TService> : IInterceptor where TService : class
{
    private readonly IChannelFactoryManager _manager;
    private TService _instance;
    private bool _instanceChanged;
 
    public WcfClientInterceptor(TService service)
        : this(service, new ChannelFactoryManager())
    {
    } 
    public WcfClientInterceptor(TService service, IChannelFactoryManager manager)
    {
        _manager = manager;
        SetupInsance(service);
        _instanceChanged = false;
    }
 
    public void Intercept(IInvocation invocation)
    {
        if (_instanceChanged)
        {
            //change the underpinning channel 
            //replaces a faulted channel with the new one
            var cpt = (IChangeProxyTarget)invocation;
            cpt.ChangeProxyTarget(_instance);
            cpt.ChangeInvocationTarget(_instance);
            _instanceChanged = false;
        }
 
        if (invocation.Method.Name == "Dispose")
        {
            //clean up the proxy
            Dispose();
            return;
        }
 
        invocation.Proceed();
    }
 
    /// <summary>
    /// close or abort the channel (clean up)
    /// </summary>
    private void Dispose()
    {
        ICommunicationObject commObj = (ICommunicationObject)_instance;
        commObj.Faulted -= OnFaulted;
        try
        {
            if (commObj.State == CommunicationState.Faulted)
            {
                commObj.Abort();
            }
            else
            {
                commObj.Close();
            }
        }
        catch
        {
            commObj.Abort();
        }
        _instance = null;
    }
 
    /// <summary>
    /// set the current channel instance
    /// </summary>
    /// <remarks>
    /// this attaches to the OnFaulted to try and clean up the proxy when it enters 
    /// a faulted state
    /// </remarks>
    private void SetupInsance(TService service)
    {
        _instance = service;
        ((ICommunicationObject)_instance).Faulted += OnFaulted;
        _instanceChanged = true; 
    } 
    /// <summary>
    /// create a new channel, using the channel factory manager
    /// </summary>
    private void CreateNewChannel()
    {
        var newInstance = _manager.CreateChannel<TService>();
        SetupInsance(newInstance);
    }
 
    /// <summary>
    /// Handle a faulted channel
    /// </summary>
    private void OnFaulted(object sender, EventArgs eventArgs)
    {
        Dispose();
        CreateNewChannel();
    }
}    

The proxy ensures there will always be a valid channel for the ViewModel to use.

The proxy has also been extended to support IDisposable, allowing for an IoC container to clean up the proxy when it is released. 

Some Tests 

The following screenshot are the tests included in the sample project. They focus on the Proxy to try and ensure the interceptor works correctly. 

Image 3

Points of Interest  

  1. We can now inject our services using their interfaces 
    • This makes Mocking easier  
    • The ViewModel does not know of any Channel maintenance
  2. We have an IDisposable interface implementation  
    • This makes cleaning up the resources slightly easier; also if you are using an IoC container, they can make use of this for you. 

The solution is only intended to be used in a stateful WPF/Silverlight application. 

History  

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)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionTell me about state maintain in WCF Pin
Tridip Bhattacharjee27-Feb-13 20:40
professionalTridip Bhattacharjee27-Feb-13 20:40 
AnswerRe: Tell me about state maintain in WCF Pin
David J Rundle3-Mar-13 9:46
David J Rundle3-Mar-13 9:46 

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.