[英]WCF Channel and ChannelFactory Caching
所以我决定在我的WCF应用程序中提高性能,并尝试缓存Channels和ChannelFactory。 关于所有这些我有两个问题,我需要在开始之前清理一下。
1)ChannelFactory应该实现为单例吗?
2)我不确定如何缓存/重用各个频道。 你有任何关于如何分享的例子吗?
值得注意的是,我的WCF服务被部署为独立应用程序,只有一个端点。
编辑:
感谢您的回复。 我还有几个问题......
1)我想我对缓存应该发生的位置感到困惑。 我正在提供一个客户端API,它将此代码用于我们公司的另一个部门。 这个缓存是否发生在客户端?
2)客户端API将用作Silverlight应用程序的一部分,这会改变什么吗? 特别是,在这种情况下可以使用哪些缓存机制?
3)我还不清楚GetChannelFactory方法的设计。 如果我只有一个服务,是否应该只创建和缓存一个ChannelFactory?
我还没有实现任何缓存功能(因为我对如何完成它完全感到困惑!),但这是我到目前为止客户端代理所拥有的:
namespace MyCompany.MyProject.Proxies
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
public Response DoSomething(Request request)
{
var channel = channelFactory.CreateChannel();
try
{
Response response = channel.DoSomethingWithService(request);
((ICommunicationObject)channel).Close();
return response;
}
catch(Exception exception)
{
((ICommenicationObject)channel).Abort();
}
}
}
使用ChannelFactory创建工厂的实例,然后缓存该实例。 然后,您可以根据需要/期望从缓存的信息创建communicatino频道。
您是否需要多渠道工厂(即,是否有多种服务)? 根据我的经验,您可以在这里看到性能的最大好处。 创建渠道是一项相当便宜的任务; 它在开始时设置一切需要时间。
我不会缓存单个通道 - 我创建它们,将它们用于操作,然后关闭它们。 如果你缓存它们,它们可能会超时并且通道会出错,那么你将不得不中止它并创建一个新的。
不确定为什么你想使用单例实现ChannelFactory,特别是如果你要创建它并缓存它,并且只有一个端点。
我稍后会有更多时间发布一些示例代码。
更新:代码示例
以下是我如何为工作中的项目实现此功能的示例。 我使用了ChannelFactory<T>
,因为我正在开发的应用程序是一个带有多个服务的n层应用程序,还会添加更多。 目标是使用一种简单的方法在应用程序的每个生命周期创建一次客户端,然后根据需要创建通信通道。 这个想法的基础不是我的(我从网上的一篇文章中得到它),尽管我根据自己的需要修改了实现。
我的应用程序中有一个静态助手类,在该类中我有一个字典和一个方法来从channelf工厂创建通信通道。
字典如下(对象是值,因为它将包含不同的通道工厂,每个服务一个)。 我在示例中将“Cache”作为一种占位符 - 将语法替换为您正在使用的任何缓存机制。
public static Dictionary<string, object> OpenChannels
{
get
{
if (Cache["OpenChannels"] == null)
{
Cache["OpenChannels"] = new Dictionary<string, object>();
}
return (Dictionary<string, object>)Cache["OpenChannels"];
}
set
{
Cache["OpenChannels"] = value;
}
}
接下来是从工厂实例创建通信通道的方法。 该方法检查工厂是否首先存在 - 如果不存在,则创建它,将其放入字典中然后生成通道。 否则,它只是从工厂的缓存实例生成一个通道。
public static T GetFactoryChannel<T>(string address)
{
string key = typeof(T.Name);
if (!OpenChannels.ContainsKey(key))
{
ChannelFactory<T> factory = new ChannelFactory<T>();
factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
factory.Endpoint.Binding = new BasicHttpBinding();
OpenChannels.Add(key, factory);
}
T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
我把这个例子从我在工作中使用的东西中删除了一些。 你可以用这种方法做很多事情 - 你可以处理多个绑定,分配身份验证凭证等等。它几乎是你的一站式购物中心,用于生成客户端。
最后,当我在应用程序中使用它时,我通常会创建一个频道,开展业务并关闭它(或者如果需要中止它)。 例如:
IMyServiceContract client;
try
{
client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress");
client.DoSomething();
// This is another helper method that will safely close the channel,
// handling any exceptions that may occurr trying to close.
// Shouldn't be any, but it doesn't hurt.
Helper.CloseChannel(client);
}
catch (Exception ex)
{
// Something went wrong; need to abort the channel
// I also do logging of some sort here
Helper.AbortChannel(client);
}
希望上面的例子能给你一些东西。 我一直在生产环境中使用类似于此的东西大约一年,而且它运行得非常好。 我们遇到的任何问题中有99%通常与应用程序之外的内容有关(外部客户端或不受我们直接控制的数据源)。
如果有任何不清楚或您有其他问题,请告诉我。
您可以随时为每个WCF合同设置ChannelFactory静态...
您应该知道,从.Net 3.5开始,出于性能原因,通道工厂会汇集代理对象。 调用ICommunicationObject.Close()
方法实际上将对象返回到池中,希望它可以被重用。
如果你想进行一些优化,我会查看探查器,如果你可以阻止在你的代码中进行一次IO调用,那么它可能远远超过你对通道工厂所做的任何优化。 不要选择要优化的区域,使用分析器查找可以定位优化的位置。 例如,如果你有一个SQL数据库,你可能会在你的查询中发现一些悬而未决的成果,如果这些尚未经过优化,它们将使你的性能提升数量级。
创建频道非常耗费性能。 实际上,如果在客户端使用ClientBase而不是纯ChannelFactory,WCF已经具有ChannelFactory的缓存机制。 但是如果您进行一些正常的操作,缓存将会过期(如果您愿意,请将其google以获取详细信息)。 对于ErOx的问题,我得到了另一种解决方案,我认为它更好。 见下文:
namespace ChannelFactoryCacheDemo
{
public static class ChannelFactoryInitiator
{
private static Hashtable channelFactories = new Hashtable();
public static ChannelFactory Initiate(string endpointName)
{
ChannelFactory channelFactory = null;
if (channelFactories.ContainsKey(endpointName))//already cached, get from the table
{
channelFactory = channelFactories[endpointName] as ChannelFactory;
}
else // not cached, create and cache then
{
channelFactory = new ChannelFactory(endpointName);
lock (channelFactories.SyncRoot)
{
channelFactories[endpointName] = channelFactory;
}
}
return channelFactory;
}
}
class AppWhereUseTheChannel
{
static void Main(string[] args)
{
ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint");
}
}
interface IMyContract { }
}
如果您有其他要求,可以自己自定义Initiate方法的逻辑和参数。 但是这个启动器类不仅限于一个端点。 它对应用程序中的所有端点都很强大。 希望。 它适合你。 BTW。 这个解决方案不是来自我。 我从一本书中得到了这个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.