【问题标题】:WCF Client Proxies, Client/Channel Caching in ASP.Net - Code ReviewWCF 客户端代理,ASP.Net 中的客户端/通道缓存 - 代码审查
【发布时间】:2012-04-30 08:09:58
【问题描述】:

长期 ASP.Net 接口开发人员被要求学习 WCF,正在寻找更多与架构相关的领域的教育 - 因为它不是我的强项,但我不得不处理。

在我们当前的 ASMX 世界中,我们采用了创建 ServiceManager 静态类的模型来与 Web 服务交互。我们开始迁移到 WCF,尝试遵循相同的模型。起初我正在处理性能问题,但我已经进行了一些调整,现在我们运行顺利,但我质疑我的策略。这是我们正在做的简化版本(删除了错误处理、缓存、对象操作等):

public static class ContentManager
{
    private static StoryManagerClient _clientProxy = null;
    const string _contentServiceResourceCode = "StorySvc";

    // FOR CACHING
    const int _getStoriesTTL = 300;
    private static Dictionary<string, GetStoriesCacheItem> _getStoriesCache = new Dictionary<string, GetStoriesCacheItem>();
    private static ReaderWriterLockSlim _cacheLockStories = new ReaderWriterLockSlim();

    public static Story[] GetStories(string categoryGuid)
    {
        // OMITTED - if category is cached and not expired, return from cache

        // get endpoint address from FinderClient (ResourceManagement SVC)
        UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);

        // Get proxy
        StoryManagerClient svc = GetStoryServiceClient(ur.Url);

        // create request params
        GetStoriesRequest request = new GetStoriesRequest{}; // SIMPLIFIED
        Manifest manifest = new Manifest{}; // SIMPLIFIED

        // execute GetStories at WCF service
        try
        {
            GetStoriesResponse response = svc.GetStories(manifest, request);
        }
        catch (Exception)
        {
            if (svc.State == CommunicationState.Faulted)
            {
                svc.Abort();
            }

            throw;
        }

        // OMITTED - do stuff with response, cache if needed
        // return....
    }

    internal static StoryManagerClient GetStoryServiceClient(string endpointAddress)
    {
        if (_clientProxy == null)
            _clientProxy = new StoryManagerClient(GetServiceBinding(_contentServiceResourceCode), new EndpointAddress(endpointAddress));

        return _clientProxy;
    }

    public static Binding GetServiceBinding(string bindingSettingName)
    {
        // uses Finder service to load a binding object - our alternative to definition in web.config
    }

    public static void PreloadContentServiceClient()
    {
        // get finder location
        UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);

        // preload proxy
        GetStoryServiceClient(ur.Url);
    }    
}

我们现在运行顺利,往返调用在 100 毫秒范围内完成。创建 PreloadContentServiceClient() 方法并添加到我们的 global.asax 使“第一次调用”性能下降到相同的水平。您可能想知道我们正在使用 DataContractSerializer 和“添加服务引用”方法。

我已经阅读了大量关于静态类、单例、共享数据协定程序集、如何使用 ChannelFactory 模式以及我可以对我们的使用模型做的一大堆其他事情......诚然,其中一些它超越了我的头。而且,就像我说的,我们似乎运行得很顺利。不过,我知道我没有看到大局。有人能告诉我关于通道池、代理故障等的结果,以及为什么我应该沿着 ChannelFactory 路径前进吗?我的直觉告诉我去​​做,但我的脑袋无法理解为什么......

谢谢!

【问题讨论】:

  • 您应该在问题中包含您的异常处理代码,因为它与 WCF 代理相关。请参阅此blog post,简要概述异常处理的必要逻辑。此外,尝试使用 WCF 服务和客户端更改为在您的配置中使用 netTcpBinding 来创建您的应用程序的负载测试。如果有任何事情会导致对 WCF 代理的不当处置会导致 netTcpBinding 持续负载。
  • 我刚刚在上面代码中的服务操作周围添加了 try/catch 块。在这一点上没有什么特别的。我在您链接的博客文章中注意到的一件事是在操作完成后使用 client.Close() 。如果我要关闭客户端,这是否会破坏让通道准备就绪以加快下一次通话的目的?
  • Microsoft 在为 WCF 通道实现 IDisposable 时做出了某些设计决策,这些通道需要类似于我引用的使用模式,以便正确释放网络资源。如果您的 WCF 服务由每分钟有几个请求的客户端调用,那么您通常可以允许 .NET GC 最终恢复资源。你应该阅读这个问题的blog post for a good discussion,点击里面的链接来获取完整的故事。

标签: asp.net wcf proxy client channelfactory


【解决方案1】:

ChannelFactory 通常在您不使用 添加服务参考 时使用 - 您通过共享程序集而不是通过 WSDL 生成合同。 添加服务参考 使用ClientBase,它实质上是在幕后为您创建 WCF 通道。

当您处理 REST-ful 服务时,WebChannelFactory 提供了一个基于共享组装合同的服务客户端类接口。如果您的服务仅支持 REST-ful 端点绑定,则不能使用添加服务引用。

对您而言唯一的区别是偏好 - 您是否需要完全访问通道以进行自定义行为、绑定等,或者 添加服务参考 + SOAP 是否为您提供了足够的接口来满足您的需求.

【讨论】:

  • 我们喜欢为每个方法调用使用请求和响应对象的模型。它可以很容易地保持服务向后兼容,而不必一次升级客户端的所有实例……比如向请求对象添加另一个过滤器或向响应添加一个附加字段。如果这两种方法都可以用来实现相似的输出,那么我们宁愿没有类型化的共享数据合约。而且这里不需要 REST,但至少……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2011-09-28
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
相关资源
最近更新 更多