I have to admit I am not a huge fan of the automatic proxy generated code that you can obtain with svcutil.exe or using a standard Visual Studio service reference; mainly because it’s bloated with a lot of unneeded code, especially if you develop the service AND the clients that will use it (don’t get me wrong, the generated code is very useful if you do not have full control over the service or you are using a 3rd party WCF service).

Let’s put us in the good case in which we develop the service and the consumer and we have full control over the assemblies that defines the contract of the service and the classes that will be used to exchange data.

Some friends of mine (Andrea Balducci and Gian Maria Ricci) already showed you a simple technique to use Castle Windsor to host a WCF service), let’s now complete the picture and see how you can use the IoC container to generate a proxy on the client to consume those services.

But first of all you have to keep in mind that all you need to use a WCF is just an interface that matches the one exposed by the service (and eventually that extends it with asynchronous methods) and a set of classes used to exchange data (if the service itself does not expose only basic types).

Let’s consider we have a test WCF service with a contract like this:

[ServiceContract]
public interface IServerService
{
    [OperationContract]
    [FaultContract(typeof(ServiceError))]
    string Echo(string message);
 
    [OperationContract]
    [FaultContract(typeof(ServiceError))]
    ComplexTestData ExtendedEcho(string message);
}
 
public class ComplexTestData
{
    public string Message { get; set; }
    public DateTime Timestamp { get; set; }
}

We suppose to have the interface defined in an assembly separated from the real implementation, all you have to do to use it on the client is to make a reference to this assembly (or create a matching interface) and create a proxy with something like:

IServerService service = new ChannelFactory<IServerService>("endpointconfig").CreateChannel();

Here I am assuming you have the configuration for an endpoint called “endpointconfig” in your app.config file.

Done! That’s all you need, no code generation, no svcutil or whatever, you can start using your service immediately.

It would be nice if we can instrument the IoC container, Castle Windsor in our case, and make him able to create instances proxy services based on the instances we register in it. We can later take advantage of a series of features like AOP that these IoC/DI containers can offer.

The first step is to find a way to create a channel given a service interface contract, this can be easily done using reflection:

public static object CreateWcfChannelProxy(Type service, string endpoint)
{
    Type channelFactoryBaseType = typeof(ChannelFactory<>);
    channelFactoryBaseType = channelFactoryBaseType.MakeGenericType(service);
    // Create an instance
    object instance = Activator.CreateInstance(channelFactoryBaseType, endpoint);
    MethodInfo createchannel = instance.GetType().GetMethod("CreateChannel", new Type[0]);
    return createchannel.Invoke(instance, null);
}

The last step is to build a Facility that uses that code and it’s able to create instances of the channel proxies based on a configuration we provide.

We want to be able to configure our service on the client using the following XML snippet (Castle Windsor configuration file):

<configuration xmlns="http://www.tigraine.at/windsor-configuration.xsd">
  <facilities>
    <facility id="wcfproxycreation"
              type="Structura.Castle.Windsor.WcfProxyCreationFacility, Structura.Castle.Windsor" >
      <wcfservice id="custominterfaceservice"
                  service="KilogWms.Services.Test.ServerTest.IServerService, KilogWms.Services.Test"
                  endpoint="WSHttpBinding_CustomIServerService"
                  lifestyle="Transient" />
    </facility>
  </facilities>
</configuration>

The “wcfservice” declaration is intentionally similar to a normal component declaration, here you can specify an id for the service, the service interface that represent the ServiceContract, an endpoint configuration (must match one available in the app.config file), the lifestyle and the customLifestyleType to be associated with the service. You can register how many services you want.

I’m not a Castle guru and the actual implementation of the facility gave me some troubles...till I discovered the IComponentActivator and all its implementations, basically you can associate to each component you register in the container a specific class that takes care of generating a live instance of the object based on the information you provide. Armed with this knowledge we can write our custom activator:

public class WcfProxyActivator : DefaultComponentActivator
{
    public WcfProxyActivator(ComponentModel model, IKernel kernel,
    ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
        : base(model, kernel, onCreation, onDestruction)
    {}
 
    /// <summary>
    /// create a wcf channel through reflection
    /// </summary>
    /// <param name="service">the interface of the service</param>
    /// <param name="endpoint">the service end point (can be retrieved from the extededproperties associated with the Model</param>
    /// <returns></returns>
    public static object CreateWcfChannelProxy(Type service, string endpoint)
    {
        Type channelFactoryBaseType = typeof(ChannelFactory<>);
        channelFactoryBaseType = channelFactoryBaseType.MakeGenericType(service);
        // Create an instance
        object instance = Activator.CreateInstance(channelFactoryBaseType, endpoint);
        MethodInfo createchannel = instance.GetType().GetMethod("CreateChannel", new Type[0]);
        return createchannel.Invoke(instance, null);
    }
 
    public override object Create(CreationContext context)
    {
        string endpointconfiguration = (string)Model.ExtendedProperties["EndPointConfig"];
        return CreateWcfChannelProxy(Model.Service, endpointconfiguration);
    }
 
}

The facility is straightforward:

/// <summary>
/// a facility that allows the creation of WCF proxies simply registrering the interfaces in the windsor container
/// </summary>
public class WcfProxyCreationFacility : AbstractFacility
{
    protected override void Init()
    {
        foreach (IConfiguration child in FacilityConfig.Children)
        {
            if (child.Name == "wcfservice")
            {
                // read the configuration for a single service
                string id = child.Attributes["id"];
                string service = child.Attributes["service"];
                string lifestyle = child.Attributes["lifestyle"];
                string endpointconfiguration = child.Attributes["endpoint"];
                string customLifestyleType = child.Attributes["customLifestyleType"];
 
                Type serviceType = Type.GetType(service);
                if (serviceType == null)
                    throw new ArgumentException(string.Format("service argument: {0} cannot be succesfully converted to a Type", service));
                
                // create the information and the structures needed to register the service in the IoC
                ComponentModel model = new ComponentModel(id, serviceType, typeof(object));
                model.ExtendedProperties["EndPointConfig"] = endpointconfiguration;
                // this is the key part the componentactivator
                model.CustomComponentActivator = typeof(WcfProxyActivator);
                if (!string.IsNullOrEmpty(lifestyle))
                    model.LifestyleType = (LifestyleType)Enum.Parse(typeof (LifestyleType), lifestyle);
                if (!string.IsNullOrEmpty(customLifestyleType))
                    model.CustomLifestyle = Type.GetType(customLifestyleType);
                
                // todo: set extended properties
                Kernel.AddCustomComponent(model);
            }
        }
    }
}

Here’s how you can instantiate a proxy from a WCF service using this facility:

   1: // lets create the container and load its configuration
   2: WindsorContainer cont = new WindsorContainer("Windsor.xml");
   3: IServerService service = cont.Resolve<IServerService>();
   4: var response = service.Echo("hello");
   5: Assert.That("hello", Is.EqualTo(response));
   6: // try a complex call
   7: ComplexTestData complexresponse = service.ExtendedEcho("extended hello");
   8: Assert.IsNotNull(complexresponse);
   9: Assert.That("extended hello", Is.EqualTo(complexresponse.Message));
  10: Assert.IsInstanceOfType(typeof(DateTime), complexresponse.Timestamp);
  11: // now try an async call
  12: service.BeginEcho("helloAsync",
  13:                   (result) =>
  14:                       {
  15:                           string res = ((IServerService) result.AsyncState).EndEcho(result);
  16:                           Assert.That("helloAsync", Is.EqualTo(res));
  17:                       },
  18:                   service);

You don’t need to use any ServiceReference or any svcutil generated code, if you want to have async method (like in the example above) all you have to do is define your interface (by deriving from the server interface class or by writing a new one from scratch) for the service and provide the methods with the right signature.

Related Content