WCF通道工厂缓存

Mor*_*hed 1 c# wcf

WCF服务将使用另一个Wcf服务.现在,我想创建通道工厂对象并手动缓存它.我知道表现会很好,但会引起任何其他问题的关注.

我发现信息如下:

"使用ChannelFactory,您仍然可以使用自己的自定义MRU缓存实现通道工厂缓存.这仍然意味着一个重要的限制:对共享通道工厂的同一服务端点的调用也必须共享相同的凭据.这意味着您无法传递不同的凭据对于从Web服务器层调用应用程序服务的每个线程.如果您使用相同的证书或Windows凭据对下游服务进行身份验证,则会出现这种情况.在这种情况下,如果您需要传递有关经过身份验证的用户的信息,您可以使用自定义标头而不是安全令牌."

链接:http://devproconnections.com/net-framework/wcf-proxies-cache-or-not-cache

我在Google中找到了一个示例代码,如下所示.

internal delegate void UseServiceDelegate<in T>(T proxy);



    internal static class Service<T>
   {

      private static readonly IDictionary<Type, string>  
                 cachedEndpointNames   =    new  Dictionary<Type, string>();


private static readonly IDictionary<string, ChannelFactory<T>> 
    cachedFactories =
    new Dictionary<string, ChannelFactory<T>>();


     internal static void Use(UseServiceDelegate<T> codeBlock)
     {
        var factory = GetChannelFactory();
        var proxy = (IClientChannel)factory.CreateChannel();
        var success = false;

      try
      {
        using (proxy)
        {
            codeBlock((T)proxy);
        }

        success = true;
    }
    finally
    {
        if (!success)
        {
            proxy.Abort();
        }
    }
}


     private static ChannelFactory<T> GetChannelFactory()
     {
      lock (cachedFactories)
      {
        var endpointName = GetEndpointName();

        if (cachedFactories.ContainsKey(endpointName))
        {
            return cachedFactories[endpointName];
        }

        var factory = new ChannelFactory<T>(endpointName);

        cachedFactories.Add(endpointName, factory);
        return factory;
        }
    }


     private static string GetEndpointName()
     {
        var type = typeof(T);
        var fullName = type.FullName;

    lock (cachedFactories)
    {
        if (cachedEndpointNames.ContainsKey(type))
        {
            return cachedEndpointNames[type];
        }

        var serviceModel =  

     ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
     .SectionGroups["system.serviceModel"] as ServiceModelSectionGroup;

        if ((serviceModel != null) && !string.IsNullOrEmpty(fullName))
        {
            foreach (var endpointName in  
    serviceModel.Client.Endpoints.Cast<ChannelEndpointElement>()
   .Where(endpoint => fullName.EndsWith(endpoint.Contract)).Select(endpoint 
    => endpoint.Name))
            {
                cachedEndpointNames.Add(type, endpointName);
                return endpointName;
            }
        }
    }

    throw new InvalidOperationException("Could not find endpoint element   
       for type '" + fullName + "' in the ServiceModel client 
      configuration section. This might be because no configuration file 
       was found for your application, or because no endpoint element 
       matching this name could be found in the client element.");
    }
 }
Run Code Online (Sandbox Code Playgroud)

我完全糊涂了该怎么办.谁能给我一个最佳实践指南?

Der*_*k W 7

这是一个复杂的主题,需要详细介绍很多细节,但在这里.

首先,作为一般规则,您应该缓存一个ChannelFactory而不是个人Channel.A ChannelFactory构造和线程安全都很昂贵,因此它是缓存的理想选择.A Channel构建起来很便宜,通常建议只根据需要创建频道并尽早关闭它们.此外,当你缓存a Channel然后你必须担心它超时会导致它出错,这首先使缓存它的全部好处失效.

您与Michele Leroux Bustamante联系的文章是最好的资源之一.正如她所说,Windows客户端和服务器端客户端之间存在差异.大多数情况下,只有Windows客户端受益于缓存,因为服务器端客户端上的凭据通常因线程而异.对于典型的Windows客户端,有两个主要选项:自己缓存引用或利用MRU缓存.

利用MRU缓存:从本质上讲,这意味着您正在让微软采取行动.该ClientBase课程将使用MRU缓存的内部ChannelFactory实例.缓存行为通过CacheSetting属性进行控制,默认情况下,如果访问任何"安全敏感"属性,将禁用缓存.ClientBase这将废止和删除一个属性ChannelFactory访问时从MRU缓存包括Endpoint,ClientCredentialsChannelFactory本身.有一种方法可以通过将CacheSettings属性设置为覆盖此行为CacheSettings.AlwaysOn.此外,如果Binding定义了运行时,ChannelFactory则不再是MRU高速缓存的候选者.在这里查看更多细节.

自己缓存引用:这意味着您将自己保留一组ChannelFactory引用.您在问题中提供的代码段使用此方法.我见过并且无可否认地使用改进版本的工作的最佳方法是Darin Dimitrov通过这个相关的SO问题.对于我们这些喜欢对缓存机制进行更细粒度控制的人来说,这就是使用方法.这通常在必须在运行时设置凭证时使用,就像互联网服务经常需要的那样.

很相似,可以缓存客户端代理以提高性能 - Wenlong Dong一篇关于此主题的文章.

(更新)如前所述,服务器端客户端在ChannelFactory缓存方面的选择非常有限.对于这个简短的讨论,我们假设我们的部署方案如下所示:

客户 - >服务A - >服务B.

ChannelFactory在此方案中,为了利用缓存而使用的最可能的方法是自己缓存客户端服务A之间的会话的引用.这样,每次服务A需要调用服务B时,服务A不必构造不同的ChannelFactory实例.但是,如果每次调用需要的属性发生变化,那么这将不再合适.ChannelFactory

当然,如果服务A是Singleton并且对下游服务(服务B)的每次调用都不需要新凭证,那么这也是成立,但Singleton服务有其自己的一组性能问题.