Correct WCF service handling using a factory and service proxies in C#

510 Views Asked by At

I have a part of my program that sends me an email and/or a push message to my iphone when something occurs. This is done through calls to two seperate WCF services using MSMQ. I followed this guide (model 4.0) in order to make it generic and test friendly. I like the generic channel creation, but my question is wether the proxies and channel factories are really closed/disposed correctly, or if this will blow up when it reaches a 10000 user environment (which it eventually will). The code works perfectly in my 50 user test environment.

Therefore, please review the following code:

Service Proxy

public class ServiceProxy<TChannel> : IServiceProxy<TChannel> where TChannel : ICommunicationObject
{
    private readonly TChannel InnerChannel;

    public ServiceProxy(TChannel innerChannel)
    {
        this.InnerChannel = innerChannel;
    }

    public void Execute(Action<TChannel> operation)
    {
        try
        {
            operation(InnerChannel);
            InnerChannel.Close();
        }
        catch (CommunicationException)
        {
            InnerChannel.Abort();
        }
        catch (TimeoutException)
        {
            InnerChannel.Abort();
        }
        catch (Exception)
        {
            InnerChannel.Abort();
            throw;
        }
    }

    public TResult Execute<TResult>(Func<TChannel, TResult> operation)
    {
        TResult result = default(TResult);

        try
        {
            result = operation(InnerChannel);
            InnerChannel.Close();
        }
        catch (CommunicationException)
        {
            InnerChannel.Abort();
        }
        catch (TimeoutException)
        {
            InnerChannel.Abort();
        }
        catch (Exception)
        {
            InnerChannel.Abort();
            throw;
        }

        return result;
    }
}

Service Proxy Factory

public class ServiceProxyFactory : IServiceProxyFactory
{
    public IServiceProxy<TChannel> GetProxy<TChannel>(string endpointName) where TChannel : ICommunicationObject
    {
        var factory = new ChannelFactory<TChannel>(endpointName);
        return new ServiceProxy<TChannel>(factory.CreateChannel());
    }
}

Making a service call (without return type for simplicity)

public class MessageSender : IMessageSender
{
    private const string PushServiceEndpoint = "PushEndpointName";
    private const string MailServiceEndpoint = "MailEndpointName";

    private readonly IServiceProxyFactory ServiceProxyFactory;

    public MessageSender()
    {
        ServiceProxyFactory = new ServiceProxyFactory();
    }

    public void NotifyMe(*some args*)
    {
        ServiceProxyFactory.GetProxy<MailServiceChannel>(MailServiceEndpoint)
                     .Execute(a => a.SendEmail(*some args*));
    }

The questions are:

Should I close the ServiceProxy after the Execute?

Is it wise to create a ChannelFactory every time I call GetProxy(), and should this ChannelFactory then be closed again if so?

Is it really performance friendly to generate a ServiceProxy for every call? (it seems really heavy to me, but maybe someone can prove me wrong).

I left the interfaces out from this post, but they are really simple, and this whole setup with proxies and interfaces works really well with unit and integration testing.

I hope some of you coding wizards have an opinion about this, and will share this.

Thanks in advance!

1

There are 1 best solutions below

2
On BEST ANSWER

The main performance impact has the creation of a ChannelFactory.

Creating ChannelFactory instances incurs some overhead because it involves the following operations: Constructing the ContractDescription tree

Reflecting all of the required CLR types

Constructing the channel stack

Disposing of resources

https://msdn.microsoft.com/en-us/library/hh314046%28v=vs.110%29.aspx

WCF team has implemented caching for ClientBase<TChannel> class, it is suitable when you have auto generated proxy classes. As you are using pure ChannelFactory you have to be careful about creating factories it on each call in order to have a better performance.

A good solution would be to implement caching of ChannelFactory<TChannel> your own (there is a good idea on how to do that). So at the end in your ServiceProxyFactory instead of having new ChannelFactory<TChannel>(endpointName); you should use cached instances like CachedChannelFactory<TChannel>.GetInstance().

Edit: There is another good article written by Michele Leroux Bustamante, that explains when To Cache or Not to Cache