0

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!

ruNury
  • 35
  • 4

1 Answers1

1

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

Community
  • 1
  • 1
Andrei Mihalciuc
  • 2,148
  • 16
  • 14
  • Thank you for your input. Your link to "a good idea" is a really interesting read. One question though: If creating channelfactories is the expensive operation, why not fass the ChannelFactory to the proxy through constructor injection, and then have a Service proxy for each of the services? this way the Service proxy could create the channel, do something and close the channel... This way you will have one channel factory for each ServiceProxy, which is only created once. – ruNury Nov 03 '15 at 11:56
  • I think, that you solution is a viable option as well, just make sure that you control lifetime of your instances. – Andrei Mihalciuc Nov 03 '15 at 20:11