繁体   English   中英

WCF通道工厂缓存

[英]WCF channel Factory caching

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.");
    }
 }

我完全困惑我该怎么办。 谁能给我一个最佳实践指南?

这是一个复杂的主题,有很多细节需要解决,但是可以解决。

首先,作为一般规则,您应该缓存ChannelFactory而不是单个Channel ChannelFactory构造成本高且线程安全,因此非常适合缓存。 Channel构建成本低廉,通常建议仅根据需要创建通道,并尽早关闭它们。 另外,当您缓存一个Channel您必须担心它会超时,这将导致它发生故障,从而使首先缓存它的全部好处失效。

您与Michele Leroux Bustamante链接的文章是那里最好的资源之一。 如她所说,Windows客户端和服务器端客户端之间存在要考虑的差异。 通常,只有Windows客户端才能从缓存中受益,因为通常凭据在服务器端客户端上的线程之间是不同的。 对于典型的Windows客户端,有两个主要选项:自己缓存引用或利用MRU缓存。

利用MRU缓存:从本质上讲,这意味着您要让Microsoft掌控一切。 ClientBase类将对内部ChannelFactory实例使用MRU缓存。 缓存行为是通过CacheSetting属性控制的,并且默认情况下,如果访问任何“安全敏感”属性,则将禁用缓存。 被访问时会使MRU缓存无效并从MRU缓存中删除ChannelFactory ClientBase属性包括EndpointClientCredentialsChannelFactory本身。 有一种方法来覆盖通过设置这种行为CacheSettings属性CacheSettings.AlwaysOn 此外,如果Binding是在运行时定义的,则ChannelFactory不再是MRU缓存的候选者。 在这里查看更多详细信息

自己缓存引用:这意味着您将自己保留ChannelFactory引用的集合。 您在问题中提供的摘录使用此方法。 我见过的最好的方法是使用Darin Dimitrov 提出的有关SO的修改版,该方法是在工作中使用的改进版本。 对于那些希望对缓存机制进行更细粒度控制的人来说,这就是使用的方法。 通常在必须在运行时设置凭据(如Internet服务经常需要的凭据)时使用此选项。

同样,可以缓存客户端代理以提高性能-Dong Wenlong一篇有关该主题的文章

(更新)如前所述,服务器端客户端在ChannelFactory缓存方面的选择非常有限。 在此简短讨论中,我们将假定我们的部署方案如下所示:

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

为了在这种情况下利用ChannelFactory缓存,最可能使用的方法是为客户端服务A之间的会话自己缓存引用。 这样,每次服务A需要调用服务B时, 服务A不必构造不同的ChannelFactory实例。 但是,如果需要为每个调用更改ChannelFactory的属性,那么这将不再合适。

当然,如果服务A是一个Singleton,并且对下游服务( Service B )的每个调用都不需要新的凭据,则也适用,但是Singleton服务有其自身的一系列性能问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM