Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't IChannelFactory<T> define a parameter-less CreateChannel?

Tags:

.net

wcf

Why doesn't the IChannelFactory< TChannel> interface define a parameter-less CreateChannel()?

The concerete ChannelFactory< TChannel> class on the other hand does have a parameter-less CreateChannel().

For testability/SoC reasons I want to pass around IChannelFactory interface but that forces me to also pass around an EndpointAddress for use in CreateChannel(EndpointAddress).

As a workaround I have created a IChannelFactory2< IChannel> which does have a parameter-less CreateChannel().

But ultimately I'm just curious as to why it was designed like this (generally WCF has reasonable design choices, but Im just too lazy to work this one out alone!)

like image 628
Jack Ukleja Avatar asked Aug 21 '11 07:08

Jack Ukleja


2 Answers

The ChannelFactory<T>.CreateChannel() method is just a helper method, made possible by an implementation detail of the ChannelFactory<T> class.

If you look at the ChannelFactory<T> source code, you'll see this:

public TChannel CreateChannel()
{
    return this.CreateChannel(this.CreateEndpointAddress(this.Endpoint), (Uri) null);
}

The CreateEndpointAddress method is implemented internally by the abstract ChannelFactory class, which ChannelFactory<T> inherits from:

internal EndpointAddress CreateEndpointAddress(ServiceEndpoint endpoint)
{
    if (endpoint.Address == (EndpointAddress) null)
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError((Exception) new InvalidOperationException(System.ServiceModel.SR.GetString("SFxChannelFactoryEndpointAddressUri")));
    else
        return endpoint.Address;
}

As you can see, the endpoint information is already available through the ChannelFactory<T>.Endpoint property, which is initialized through the various constructors of the ChannelFactory<T> class. These constructors, in fact, allow the consumers to specify the details of the endpoint to invoke.

Since interfaces cannot define constructors, the most appropriate way to pass that required piece of information is through the arguments of the method that is going to use it, that is the CreateChannel method.

like image 145
Enrico Campidoglio Avatar answered Oct 31 '22 12:10

Enrico Campidoglio


I encountered the same problem.

My solution was using a factory pattern -

public interface IFactory<out T>
{
    T CreateInstance();
}

public class WCFChannelFactory<TService> : IFactory<TService>
{
    public ChannelFactory<TService> ChannelFactory { get; set; }

    public WCFChannelFactory(ChannelFactory<TService> channelFactory)
    {
        ChannelFactory = channelFactory;
    }

    public TService CreateInstance()
    {
        return ChannelFactory.CreateChannel();
    }
}

Then in my application I just use IFactory.

like image 40
Maxim Avatar answered Oct 31 '22 13:10

Maxim