65.9K
CodeProject is changing. Read more.
Home

Pattern for Creating Generic WCF Services

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (3 votes)

Nov 28, 2011

CPOL

2 min read

viewsIcon

46315

downloadIcon

1056

A pattern for creating generic WCF services.

Introduction

I work on a solution that makes a lot of use of Generics. We have just started to add in a Silverlight control to the solution and we are using WCF to communicate with the existing code base.

I have looked around to find a solution where by we could have generic services that make use of the existing generic model. I didn't really find what I was looking for so I have come up with a test project that presents a pattern for generic services and I would like to put it out there to see what others think of it.

Using the Code

This project contains a base service class with a corresponding contract class that are both generic.

[ServiceContract]
interface IBaseService<T> where T : class, INumber
{ 
    [OperationContract]
    string GetData(int value); 
}

public class BaseService<T> : IBaseService<T>
    where T : class, INumber
{
    private T _num;

    public BaseService(INumberFactory<t> numberFactory)
    {
         _num = numberFactory.Create();
    }

    public string GetData(int value)
    {
        var ret = value * _num.Get();

        return ret.ToString();
    }
}

This base service class also has a dependency that will be resolved based on the type of T. This is just a basic factory class that will new up instances of our different type classes.

Here is the interface INumber with a couple of basic implementations:

public class NumberOne : INumber
{
    public int Get()
    {
        return 1;
    }
}

public class NumberTwo : INumber
{
    public int Get()
    {
        return 2;
    }
}

public interface INumber
{
    int Get();
}

The next stage is to declare some .svc files, one for each type we want the service to be used with; in this instance, one for NumberOne and one for NumberTwo. Here we need to specify the full assembly details of our type class.

ServiceOne.svc
<%@ ServiceHost Language="C#" Debug="true" 
     Service="Service.BaseService`1[[Service.NumberOne, Service, 
              Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
     Factory="Service.Host.Factory" %>
ServiceTwo.svc
<%@ ServiceHost Language="C#" Debug="true" 
    Service="Service.BaseService`1[[Service.NumberTwo, Service, 
             Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]" 
    Factory="Service.Host.Factory" %>

As you can see, here we are using a Factory class to create instances of our service host. This allows us to use a custom ServiceHost class.

public class Factory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var host = new UnityServiceHost(serviceType, baseAddresses);

        return host;
    }
}

Our custom service host class will add a new behaviour that will allow us to manipulate the endpoints of our services.

public class UnityServiceHost : ServiceHost
{
    private  IUnityContainer _unityContainer;

    public UnityServiceHost(Type serviceType, Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
    }

    protected override void OnOpening()
    {
        base.OnOpening();

        if (this.Description.Behaviors.Find<unityservicebehavior>() == null)
            this.Description.Behaviors.Add(new UnityServiceBehavior());
    }
}

For each endpoint on our service, we now apply a custom instance provider.

public class UnityServiceBehavior : IServiceBehavior
{
    private readonly IUnityContainer container;

    public UnityServiceBehavior()
    {
    }

    public void Validate(ServiceDescription serviceDescription, 
                         ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, 
           ServiceHostBase serviceHostBase, Collection<serviceendpoint> endpoints, 
           BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
                ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
            {
                string contractName = endpointDispatcher.ContractName;
                if (contractName != "IMetadataExchange" && 
                    contractName != "IHttpGetHelpPageAndMetadataContract")
                {
                    ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(
                              e => e.Contract.Name == contractName);
                    endpointDispatcher.DispatchRuntime.InstanceProvider = 
                        new UnityInstanceProvider(serviceEndpoint.Contract.ContractType);
                }
            }
        }
    }
}

This instance provider will now use Unity to create the service and all its dependencies.

public class UnityInstanceProvider : IInstanceProvider
{
    private readonly Type contractType;
    public UnityInstanceProvider(Type contractType)
    {
        this.contractType = contractType;
    }
    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }
    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return IocManager.Container.Resolve(contractType);
    }
    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        IocManager.Container.Teardown(instance);
    }
}

Finally, we have the IocManager that contains the configuration for our dependencies.

public class IocManager
{
    private static IUnityContainer _container;
    private static object _syncRoot = new object();

    public static IUnityContainer Container
    {
        get
        {
            if (_container == null)
                lock (_syncRoot)
                {
                    _container = GetIocContainer();
                }
            return _container;
        }
    }

    private static IUnityContainer GetIocContainer()
    {
        IUnityContainer container = new UnityContainer();

        ConfigureUnityContainer(container);

        return container;
    }

    private static void ConfigureUnityContainer(IUnityContainer container)
    {
        container.RegisterType<ibaseservice<numberone>, 
                  BaseService<numberone>>();

        container.RegisterType<ibaseservice<numbertwo>, 
                  BaseService<numbertwo>>();

        container.RegisterType<inumberfactory<numberone>, NumberFactoryOne>();

        container.RegisterType<inumberfactory<numbertwo>, NumberFactoryTwo>();
    }
}

Points of Interest

I think this is a nice enough way of creating generic services. The only thing I don't really like is the fact that I need to include all the assembly information for the type declarations in the .svc classes as this could turn into a bit of a maintenance nightmare.

But I would be very interested in any other thoughts others might have on this design.

OSZAR »