WCF客户端代理,ASP.Net中的客户端/通道缓存-代码审阅

WCF客户端代理,ASP.Net中的客户端/通道缓存-代码审阅,asp.net,wcf,proxy,client,channelfactory,Asp.net,Wcf,Proxy,Client,Channelfactory,长期以来ASP.Net界面开发人员被要求学习WCF,寻求更多与体系结构相关的前沿知识——这不是我的强项,但我必须处理 在我们当前的ASMX世界中,我们采用了创建ServiceManager静态类的模型来与web服务交互。我们开始迁移到WCF,尝试遵循相同的模型。起初我是在处理性能问题,但我做了一些调整,我们现在运行顺利,但我质疑我的战术。下面是我们所做工作的简化版本(删除了错误处理、缓存、对象操作等): public static class ContentManager { priva

长期以来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);
    }    
}
公共静态类ContentManager
{
私有静态StoryManagerClient _clientProxy=null;
常量字符串\u contentServiceResourceCode=“StorySvc”;
//用于缓存
const int_getStoriesTTL=300;
私有静态字典_getStoriesCache=new Dictionary();
私有静态ReaderWriterLockSlim _cacheLockStories=new ReaderWriterLockSlim();
公共静态故事[]GetStories(string categoryGuid)
{
//省略-如果类别已缓存且未过期,则从缓存返回
//从FinderClient(ResourceManagement SVC)获取端点地址
URLROURCE ur=FinderClient.getURLROURCE(_contentServiceResourceCode);
//获取代理
StoryManagerClient svc=GetStoryServiceClient(ur.Url);
//创建请求参数
GetStoriesRequest=new GetStoriesRequest{};//简化
清单=新清单{};//简化
//在WCF服务上执行GetStories
尝试
{
GetStoriesResponse=svc.GetStories(清单、请求);
}
捕获(例外)
{
if(svc.State==CommunicationState.Faulted)
{
svc.Abort();
}
投掷;
}
//省略-处理响应,缓存(如果需要)
//返回。。。。
}
内部静态StoryManager客户端GetStoryServiceClient(字符串端点地址)
{
如果(_clientProxy==null)
_clientProxy=newstorymanagerclient(GetServiceBinding(_contentServiceResourceCode),newendpointaddress(EndpointAddress));
返回clientProxy;
}
公共静态绑定GetServiceBinding(字符串bindingSettingName)
{
//使用Finder服务加载绑定对象—web.config中定义的替代方法
}
公共静态空预加载ContentServiceClient()
{
//获取查找器位置
URLROURCE ur=FinderClient.getURLROURCE(_contentServiceResourceCode);
//预加载代理
GetStoryServiceClient(ur.Url);
}    
}
我们现在运行顺利,往返通话在100毫秒范围内完成。创建PreloadContentServiceClient()方法并将其添加到我们的global.asax中,使“第一次调用”的性能下降到了相同的水平。您可能想知道我们正在使用DataContractSerializer和“添加服务引用”方法

我已经读了很多关于静态类、单例、共享数据契约程序集、如何使用ChannelFactory模式以及我可以对我们的使用模型所做的一大堆其他事情的书……诚然,其中一些已经超出了我的理解。而且,正如我所说的,我们似乎进展顺利。不过,我知道我看不到大局。有人能告诉我,关于通道池、代理失败等,我在这里的结局是什么,以及我为什么要走ChannelFactory之路?我的直觉告诉我去做,但我的脑袋不明白为什么

谢谢

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

在处理REST-ful服务时,会根据共享程序集契约提供类似服务客户端的接口。如果您的服务只支持REST-ful端点绑定,则不能使用添加服务引用

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

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

在处理REST-ful服务时,会根据共享程序集契约提供类似服务客户端的接口。如果您的服务只支持REST-ful端点绑定,则不能使用添加服务引用


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

您应该在问题中包含异常处理代码,因为它与WCF代理相关。有关异常处理所需逻辑的简要概述,请参见此。另外,尝试在WCF服务和客户端更改为使用配置中的netTcpBinding的情况下创建应用程序的负载测试。如果有任何事情会暴露出对WCF代理的不当处理,那就是netTcpBinding的持续负载。我只是在上面的代码中围绕服务操作添加了try/catch块。在这一点上没什么特别的。我在您链接的博文中注意到的一件事是在操作完成后使用client.Close()。如果我要关闭客户端,这是否违背了让频道做好准备以加速下一次通话的目的?微软做出了某些设计决策