Click here to Skip to main content
15,881,559 members
Articles / Web Development / ASP.NET
Tip/Trick

Injection of WCF proxies in ASP.NET MVC controllers using Castle Windsor

Rate me:
Please Sign up or sign in to vote.
4.80/5 (7 votes)
12 Sep 2012CPOL2 min read 31.8K   1.1K   10   3
This tip shows how to inject WCF proxies into controllers using Castle Windsor Interceptors.

Introduction

There is a growing number of ASP.NET MVC projects which consume WCF services. We as professionals want to keep our controllers clean and easily testable. Here is the list of obvious options to enable ASP.NET MVC controllers to consume WCF services:

  1. Create a helper class which will encapsulate the WCF ChannelFactory:
  2. Here is a possible implementation:

    C#
    public class WcfClientProvider<T> : IDisposable
    {
        private ChannelFactory<T> factory;
    
        public WcfClientProvider()
        {
            factory= new ChannelFactory<T>(string.Empty);
            Open();
        }
    
        public object GetProxy()
        {
            return factory.CreateChannel();
        }
    
        public void Open()
        {
            if (this.factory.State != CommunicationState.Opened)
            {
                factory.Open();
            }
        }
    
        public void Dispose()
        {
            factory.Close();
        }

    This class can be used in a controller:

    C#
    public class ProductController : Controller
    {              
        public ViewResult ProductList()
        {
            List<Product> result = null;
            using (var client = new WcfClientProvider<IProductService>())
            {
                result = client.GetProducts();
            }
    
            return View(result);
        }
    }

    Howether, there are problems with this code. Firstly the controller action is not testable at all and secondly the syntax is verbose and you have to remember to always use using when creating the WcfClientProvider.

  3. A much better option would be to create a facade for a WCF service interface and use constructor dependency injection in the controller, like in the example below:
  4. C#
    public class WcfProductSerivceProxy : IProductService
    {
        public IList<Product> GetProducts()
        {
            List<Product> result = null;
            using (var client = new WcfClientProvider<IProductService>())
            {
               result = client.GetProxy().GetProducts();
            }
            return result;
        }
        public IList<Product> GetProductsByCategory(string category)
        {
            List<Product> result = null;
            using (var client = new WcfClientProvider<IProductService>())
            {
                result = client.GetProxy().GetProductsByCategory(category);
            }
            return result;
        }  
    }
        public class ProductController : Controller
        {
            private IProductService productService;
            public ProductController(IProductService productService)
            {           
                this.productService = productService;
            }
            public ViewResult ProductList()
            {
                return View(this.productService.GetProducts());
            }
        }

    The code above looks almost fine. It is easily testable and clean, except the fact that you have to create such a facade for every WcfInterface in your solution, which is really a boring code to write and clearly violates the Don't Repeat Yourself principle.

The solution

Ideally we would like to have something like in the option two example, but without the need to write tons of facade code. This is where Castle Windsor can help. We can create an interceptor for a WCF interface which will exactly mimic the code in the facade classes. Here is how it is done:

C#
public class WcfInterceptor : IInterceptor
{
    public IClientFactory ClientFactory { get; set; }

    public void Intercept(IInvocation invocation)
    {
        var clientProvider = ClientFactory.GetClientProvider(invocation.Method.DeclaringType);
        using(clientProvider)
        {
            invocation.ReturnValue = CallClientProviderMethod(invocation, clientProvider);
        }            
    }

    private object CallClientProviderMethod(IInvocation invocation, IClientProvider clientProvider)
    {
        var proxy = clientProvider.GetProxy();
        return invocation.Method.Invoke(proxy, invocation.Arguments);
    }
}

Here the ClientFactory returns a generic helper class, for instance WcfClientProvider<IProductService>. The code for the Client factory is shown below:

C#
public interface IClientFactory
{
     IClientProvider GetClientProvider(Type type);
}

public class WcfClientFactory : IClientFactory
{
    public IClientProvider GetClientProvider(Type type)
    {
        var closedType = typeof(WcfClientProvider<>).MakeGenericType(type);
        return (IClientProvider)Activator.CreateInstance(closedType);
    }
}

Let me explain what is going on here. WcfInterceptor is registered for each WcfInterface in the solution (later I will show how to do that) using the WindsorCastle Dependency Injection container. It means that for any call to a WcfInterface, the intercept method will be called. For example, when calling productService from a controller action:

C#
public ViewResult ProductList()
{
    return View(this.productService.GetProducts());
}

the intercept method on WcfInterceptor will be invoked. Then we call the intercepted method on the WcfProxy object:

C#
private object CallClientProviderMethod(IInvocation invocation, IClientProvider clientProvider)
{
     var proxy = clientProvider.GetProxy();
     return invocation.Method.Invoke(proxy, invocation.Arguments);
}

Here is the Windsor Castle installer code: 

C#
public class Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                            .BasedOn<IController>()
                            .LifestyleTransient());
        container.Register(Component
           .For<IInterceptor>()
           .ImplementedBy<WcfInterceptor>()
           .Named("wcf"));
        container.Register(Types
            .FromAssemblyContaining<IProductService>()
            .Where(x => x.IsInterface)
            .LifestyleTransient()
            .Configure(x => 
                {var res = x.Interceptors(InterceptorReference.ForKey("wcf")).Anywhere;} ));
                      
        container.Register(Component
            .For<IClientFactory>()
            .ImplementedBy<WcfClientFactory>());
    }
}

With the first container.Register call, we register all Controllers in the current assembly. The second call registers the WcfInterceptor. The third call registers all WcfInterfaces from the shared library with WcfInterceptor. And finally WcfClientFactory which is capable of creating a closed WcfClientProvider<T>

You can find a working solution in the accompanying download. 

Using the code 

When running locally, the solution make sure the port in ASP.NET MVC web.config matches the port for WcfProject, otherwise ASP.NET MVC will not be able to communicate with the WCF service project. 

History 

Initial version.

License

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


Written By
Team Leader Endava
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

 
QuestionUse of IclientFactory in WcfInterceptor class Pin
rajaaj27-Mar-18 1:43
rajaaj27-Mar-18 1:43 
QuestionExcellent. Is there a way to do this in Unity? Pin
Member 918553810-Dec-14 5:53
Member 918553810-Dec-14 5:53 
GeneralMy vote of 5 Pin
ksafford25-Sep-13 8:53
ksafford25-Sep-13 8:53 

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.