在 C# 中使用工厂和服务代理更正 WCF 服务处理
Correct WCF service handling using a factory and service proxies in C#
我的程序有一部分会在发生某些事情时向我的 iphone 发送电子邮件 and/or 推送消息。这是通过使用 MSMQ 调用两个单独的 WCF 服务来完成的。我遵循 this 指南(模型 4.0)以使其通用且测试友好。我喜欢通用通道创建,但我的问题是代理和通道工厂是否真的 closed/disposed 正确,或者当它达到 10000 个用户环境(它最终会)时是否会爆炸。该代码在我的 50 个用户测试环境中完美运行。
因此,请查看以下代码:
服务代理
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;
}
}
服务代理工厂
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());
}
}
进行服务调用(为简单起见,不输入 return)
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*));
}
问题是:
执行后是否需要关闭ServiceProxy?
每次调用 GetProxy() 时都创建一个 ChannelFactory 是否明智,如果是这样,是否应该再次关闭此 ChannelFactory?
每次调用都生成一个ServiceProxy真的性能友好吗? (这对我来说似乎很沉重,但也许有人可以证明我是错的)。
我从这个 post 中省略了接口,但它们真的很简单,而且这个带有代理和接口的整个设置非常适合单元和集成测试。
我希望你们中的一些编码向导对此有意见,并会分享这个。
提前致谢!
主要的性能影响是创建 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 团队已经为 ClientBase<TChannel>
class 实现了缓存,当你有自动生成的代理 classes 时它是合适的。
当您使用纯 ChannelFactory
时,您必须小心在每次调用时创建工厂,以获得更好的性能。
一个好的解决方案是实现自己的 ChannelFactory<TChannel>
缓存(a good idea 介绍了如何做到这一点)。所以最后在你的 ServiceProxyFactory
而不是 new ChannelFactory<TChannel>(endpointName);
你应该使用像 CachedChannelFactory<TChannel>.GetInstance()
.
这样的缓存实例
编辑: Michele Leroux Bustamante 写了另一篇很好的文章,解释了 To Cache or Not to Cache
我的程序有一部分会在发生某些事情时向我的 iphone 发送电子邮件 and/or 推送消息。这是通过使用 MSMQ 调用两个单独的 WCF 服务来完成的。我遵循 this 指南(模型 4.0)以使其通用且测试友好。我喜欢通用通道创建,但我的问题是代理和通道工厂是否真的 closed/disposed 正确,或者当它达到 10000 个用户环境(它最终会)时是否会爆炸。该代码在我的 50 个用户测试环境中完美运行。
因此,请查看以下代码:
服务代理
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;
}
}
服务代理工厂
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());
}
}
进行服务调用(为简单起见,不输入 return)
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*));
}
问题是:
执行后是否需要关闭ServiceProxy?
每次调用 GetProxy() 时都创建一个 ChannelFactory 是否明智,如果是这样,是否应该再次关闭此 ChannelFactory?
每次调用都生成一个ServiceProxy真的性能友好吗? (这对我来说似乎很沉重,但也许有人可以证明我是错的)。
我从这个 post 中省略了接口,但它们真的很简单,而且这个带有代理和接口的整个设置非常适合单元和集成测试。
我希望你们中的一些编码向导对此有意见,并会分享这个。
提前致谢!
主要的性能影响是创建 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 团队已经为 ClientBase<TChannel>
class 实现了缓存,当你有自动生成的代理 classes 时它是合适的。
当您使用纯 ChannelFactory
时,您必须小心在每次调用时创建工厂,以获得更好的性能。
一个好的解决方案是实现自己的 ChannelFactory<TChannel>
缓存(a good idea 介绍了如何做到这一点)。所以最后在你的 ServiceProxyFactory
而不是 new ChannelFactory<TChannel>(endpointName);
你应该使用像 CachedChannelFactory<TChannel>.GetInstance()
.
编辑: Michele Leroux Bustamante 写了另一篇很好的文章,解释了 To Cache or Not to Cache