Creating WCF client proxies with Unity

Jun 19, 2008 at 3:46 AM
Hi there,

I'm attempting to use Unity to create client proxies for WCF services based on the ServiceContract interface.  It's similar to this thread (http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=25186) except for the client-side.

I started looking at Unity and eventually found myself in ObjectBuilder land with strategies, policies, prebuildup, postbuildup and quickly lost my way.  :-(  I can't figure out how to do a factory-style creation (which I'd need to do for the WCF client proxy).

I also found this post which seems close (http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=26027).   I attempted that route but received this error:

"Resolution of the dependency failed, type = "Form1", name = "". Exception message is: The current build operation (build key Build Key[WcfClient.Form1, null]) failed: The parameter service could not be resolved when attempting to call constructor WcfClient.Form1(WcfInterfaces.IService1 service). (Strategy type Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy, index 2)"

I really do think that a custom build strategy is the answer as that way I can inspect the type being created (or dependency type required) to see if it has the ServiceContractAttribute applied to it and if so use my custom factory method to instantiate it like this:

    ChannelFactory<IService1> factory = new ChannelFactory<IService1>();
    return factory.CreateChannel();

Ideas?  Is this even possible with Unity?
Jun 19, 2008 at 4:44 AM
Edited Jun 19, 2008 at 4:46 AM
Are you trying to get Unity to create proxies via the ChannelFactory and inject them into dependent objects?

If so, why don't you create the channel (proxy) and register it with RegisterInstance?
Jun 19, 2008 at 5:07 AM
Hmm... yes, I guess I could do that.  This may be a lack of knowledge of WCF on my part, but I think I'd rather not have a long-lived client WCF proxy but rather create them every time they're needed.   I suspect I have some liftime management to solve yet with either your approach or mine as I need to handle cases where the proxy goes into a fault state and cannot be "revived" and must be re-created. 

Since I posted I think I've pretty much gotten it using a slightly different method.  I need to implement support for passing in configuration to the ChannelFactory such as Endpoint Name yet.

It boils down to registering a BuilderStrategy with the UnityContainer and then in the strategy I override the PreBuildUp() method.   There's some generics magic with instantiating the ChannelFactory<T> correctly (MakeGenericType) but overall it's what I want.   Now I can define classes that take WCF service interfaces as dependencies and Unity will correctly create the proxy using a ChannelFactory<T> where T is my service interface.  (Pending proper configuration in the config file).

public override void PreBuildUp(IBuilderContext context)
{
    if (context.Existing == null)
    {
        Type serviceType = GetServiceInterfaceType(context.BuildKey);

        if (serviceType != null)
        {
            var channelType = typeof(ChannelFactory<>);
            Type constructedGenericType = channelType.MakeGenericType(serviceType);

            var factory = Activator.CreateInstance(constructedGenericType, "Default");
            MethodInfo createChannel = factory.GetType().GetMethod("CreateChannel", new Type[]{});
            context.Existing = createChannel.Invoke(factory, null);

            context.BuildComplete = true;
        }
    }
}

private Type GetServiceInterfaceType(object buildKey)
{
    Type t = BuildKey.GetType(buildKey);
    ServiceContractAttribute[] serviceContracts = t.GetCustomAttributes(typeof(ServiceContractAttribute), true) as ServiceContractAttribute[];
    if (serviceContracts != null && serviceContracts.Length > 0)
    {
        // We know that this interface is a WCF Service Contract.
        // Snatch the interface type and return it.
        return t;
    }

    return null;
}
Jun 20, 2008 at 6:37 AM
Are you willing to register your WCF proxy types with the container, or are you dead set on figuring it out on the fly?

If you're willing to register, you can use the existing static factory extension. Something like this:

public class ChannelFactoryCreator<T>
{
    public object CreateService(IUnityContainer c) {
        return new ChannelFactory<T>().CreateChannel();
    }
}

container.Configure<IStaticFactoryConfiguration>
    .RegisterFactory<IService1>(new ChannelFactoryCreator<IService1>.CreateService)
    .RegisterFactory<IService2>(new ChannelFactoryCreator<IService2>.CreateService);

-Chris

      
Jun 21, 2008 at 9:47 PM
Actually that should work great.  I'm using a convention for my WCF proxy type class names so I can still register them at start-up by enumerating the classes in that assembly.

Thanks!  (On a good note I now know a little more about OB... not alot, but a bit more. ) :-)