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!
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