简体   繁体   English

WCF通道工厂缓存

[英]WCF channel Factory caching

A WCF service will consume another Wcf service. WCF服务将使用另一个Wcf服务。 Now, i want to create channel factory object and cache it manually. 现在,我想创建通道工厂对象并手动对其进行缓存。 I know performance will be good but concern any other issue will be raised or not. 我知道性能会很好,但担心是否会引发其他问题。

I have found info as follows: 我发现信息如下:

"Using ChannelFactory you can still achieve channel factory caching with your own custom MRU cache. This still implies an important restriction: calls to the same service endpoint that share the channel factory must also share the same credentials. That means you can t pass different credentials for each thread calling application services from the Web server tier. One scenario where this is not an issue is if you use the same certificate or Windows credential to authenticate to downstream services. In this case, if you need to pass information about the authenticated user, you can use custom headers rather than a security token." “使用ChannelFactory,您仍然可以使用自己的自定义MRU缓存来实现通道工厂缓存。这仍然意味着一个重要的限制:共享通道工厂的同一服务端点的调用也必须共享相同的凭据。这意味着您不能传递不同的凭据对于从Web服务器层调用应用程序服务的每个线程,没有问题的一种情况是,如果您使用相同的证书或Windows凭据对下游服务进行身份验证,则在这种情况下,如果您需要传递有关经过身份验证的用户的信息,则可以使用自定义标头而不是安全令牌。”

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

I have found a sample code in Google as follows. 我在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.");
    }
 }

I am totally confused what should i do. 我完全困惑我该怎么办。 Can anyone give me a best practice guideline? 谁能给我一个最佳实践指南?

This is a complex topic with a lot of details to go over, but here it goes. 这是一个复杂的主题,有很多细节需要解决,但是可以解决。

First, as a general rule you should be caching a ChannelFactory and not an individual Channel . 首先,作为一般规则,您应该缓存ChannelFactory而不是单个Channel A ChannelFactory is expensive to construct as well as thread-safe so it is a great candidate for caching. ChannelFactory构造成本高且线程安全,因此非常适合缓存。 A Channel is cheap to construct and it is generally recommended to only create channels on an as-needed basis and to close them as early as possible. Channel构建成本低廉,通常建议仅根据需要创建通道,并尽早关闭它们。 Additionally, when you cache a Channel then you have to worry about it timing out which will cause it to fault which invalidates the entire benefit of caching it in the first place. 另外,当您缓存一个Channel您必须担心它会超时,这将导致它发生故障,从而使首先缓存它的全部好处失效。

The article you linked to by Michele Leroux Bustamante is one of the best resources out there. 您与Michele Leroux Bustamante链接的文章是那里最好的资源之一。 As she states, there are differences to consider between Windows clients and server-side clients. 如她所说,Windows客户端和服务器端客户端之间存在要考虑的差异。 Mostly only Windows clients benefit from caching as typically the credentials differ from thread to thread on server-side clients. 通常,只有Windows客户端才能从缓存中受益,因为通常凭据在服务器端客户端上的线程之间是不同的。 For your typical Windows clients, there are two main options: Caching the references yourself or leveraging the MRU cache. 对于典型的Windows客户端,有两个主要选项:自己缓存引用或利用MRU缓存。

Leveraging the MRU cache: Essentially this means that you are letting Microsoft take the wheel. 利用MRU缓存:从本质上讲,这意味着您要让Microsoft掌控一切。 The ClientBase class will use an MRU cache for the internal ChannelFactory instance. ClientBase类将对内部ChannelFactory实例使用MRU缓存。 The caching behavior is controlled via a CacheSetting property and by default caching will be disabled if any of the "security-sensitive" properties are accessed. 缓存行为是通过CacheSetting属性控制的,并且默认情况下,如果访问任何“安全敏感”属性,则将禁用缓存。 ClientBase properties which will invalidate and remove a ChannelFactory from the MRU cache when accessed include the Endpoint , ClientCredentials or the ChannelFactory itself. 被访问时会使MRU缓存无效并从MRU缓存中删除ChannelFactory ClientBase属性包括EndpointClientCredentialsChannelFactory本身。 There is a way to override this behavior by setting the CacheSettings property to CacheSettings.AlwaysOn . 有一种方法来覆盖通过设置这种行为CacheSettings属性CacheSettings.AlwaysOn Additionally, if the Binding is run-time defined then the ChannelFactory is no longer a candidate for the MRU cache. 此外,如果Binding是在运行时定义的,则ChannelFactory不再是MRU缓存的候选者。 See more details here . 在这里查看更多详细信息

Caching the references yourself: This means that you are going to keep a collection of ChannelFactory references yourself. 自己缓存引用:这意味着您将自己保留ChannelFactory引用的集合。 The snippet you provide in your question uses this approach. 您在问题中提供的摘录使用此方法。 The best approach I have ever seen and admittedly use a modified version of at work is by Darin Dimitrov via this related SO question . 我见过的最好的方法是使用Darin Dimitrov 提出的有关SO的修改版,该方法是在工作中使用的改进版本。 For those of us who like to have more fine-grained control over the caching mechanism then this is the approach to use. 对于那些希望对缓存机制进行更细粒度控制的人来说,这就是使用的方法。 This is typically used when credentials must be set at run-time like is often required by internet services. 通常在必须在运行时设置凭据(如Internet服务经常需要的凭据)时使用此选项。

Quite similarly, client proxies can be cached to improve performance - Wenlong Dong has an article about this topic. 同样,可以缓存客户端代理以提高性能-Dong Wenlong一篇有关该主题的文章

(Update) Server-side clients as noted before are quite limited in their options when it comes to ChannelFactory caching. (更新)如前所述,服务器端客户端在ChannelFactory缓存方面的选择非常有限。 For this brief discussion, we will assume that our deployment scenario looks like this: 在此简短讨论中,我们将假定我们的部署方案如下所示:

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

The most likely method to use in order to leverage ChannelFactory caching in this scenario is to cache the references yourself for the session between the Client and Service A . 为了在这种情况下利用ChannelFactory缓存,最可能使用的方法是为客户端服务A之间的会话自己缓存引用。 This way Service A does not have to construct a different ChannelFactory instance every time Service A needs to call into Service B . 这样,每次服务A需要调用服务B时, 服务A不必构造不同的ChannelFactory实例。 However, if the properties of the ChannelFactory need change for each call, then this is no longer going to be appropriate. 但是,如果需要为每个调用更改ChannelFactory的属性,那么这将不再合适。

Of course this also holds if Service A is a Singleton and each call to the downstream service ( Service B ) does not require new credentials, but Singleton services have their own set of performance problems. 当然,如果服务A是一个Singleton,并且对下游服务( Service B )的每个调用都不需要新的凭据,则也适用,但是Singleton服务有其自身的一系列性能问题。

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

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