【问题标题】:WCF proxy run time initialization and performance implicationWCF 代理运行时初始化和性能影响
【发布时间】:2011-09-27 04:54:39
【问题描述】:

我正在通过 ChannelFactory 类手动初始化我的代理,因为初始化此代理的配置来自其他一些配置服务(不在同一个 App.Config 中)并且为了避免初始化成本(服务调用、读取配置设置)我缓存了这个代理。我无法承担在每次操作后关闭此代理的成本,因为需要频繁执行操作。该代理的超时配置如下。

receiveTimeout="00:10:00" 
sendTimeout="00:10:00" 
closeTimeout="00:10:00"

根据我对客户端超时属性的理解,当超时超过时,我的代理的状态将是故障。对?

我想重新初始化我的代理,所以我有 2 个选项来执行此操作。

1) 我使用 ICommunicationObject.Faulted 事件处理程序,当我的代理进入故障状态时,即使我重新初始化代理。但是这种实现并不合适,因为我们没有正确地处理代理(调用 .Close() 方法),它不会从服务端释放资源并影响我的性能。

2) 我创建了一个线程,并在代理进入故障状态前几秒钟设置了它的经过时间。通过调用 .Close{) 方法正确关闭此代理并重新初始化另一个对象并缓存它。

请建议我在性能方面哪个选项好,如果有其他解决方案可以避免这个问题,请告诉我。

提前致谢。

【问题讨论】:

    标签: wcf wcf-client


    【解决方案1】:

    如果代理处于故障状态,您可以在其上调用 Abort。 如果你真的想保留代理取决于你需要什么。如果您打算使用 Duplex-Communication 或类似的东西,这可能是个好建议。如果您只是不时调用该服务,则只能在调用期间使用代理。

    我通常会自己编写一个小型代理,它只发布 Connected 和 Fault 事件。我使用首先尝试关闭代理的代码实现 IDisposable,当引发 CommunicationException 时继续中止它。

    在处理通信的代码中,我持有对此类代理对象的引用,并在关闭/故障时处理它,并在我有待处理的操作时立即打开它。 即使网络不可靠,这在客户端也能很好地工作。 在双工服务的情况下,我只需添加一个计时器,如果连接丢失,它会尝试自动重新连接。

    这是 F# 中的一个小 sn-p,演示了我使用这个非常简单的代理的方式 - 它实际上只是包装 Channel 并获取连接事件 - WcfHelper 只是一堆帮助函数来构建地址和绑定 - 这种情况是 DuplexService 的精简版本,因此它继承自 DuplexClientBase 但 正常 非双工情况是一样的。

    /// Duplex-proxy
    type private MyProxy(handler, servicename: string, server : string, port : int) =
        inherit DuplexClientBase<IWcfConnector>(handler, WcfHelper.getBinding(), WcfHelper.createEndpointAddress(servicename, server, port))
    
        let _connectionEvent = new Event<_>()
    
        do
            base.InnerDuplexChannel.Closed.Add(fun _ -> _connectionEvent.Trigger(ConnectionState.Disconnected))
            base.InnerDuplexChannel.Opened.Add(fun _ -> _connectionEvent.Trigger(ConnectionState.Connected))
            base.InnerDuplexChannel.Faulted.Add(fun _ -> _connectionEvent.Trigger(ConnectionState.Disconnected))
    
        /// sample-Operation
        member i.TestCall(message) = base.Channel.TestCall(message)
    
        interface IDisposable with
            member i.Dispose() =
                try
                    i.Close()
                with
                | :? CommunicationException ->
                    i.Abort()
    

    【讨论】:

    • 调用 Abort() 只会从客户端释放资源。在调用 Close() 时,也会从服务端释放资源。例如,如果我设置 MaxConcurrentInstances = 1 和 InstanceContextMode = PerCall,这意味着单个代理实例可以一次服务/连接服务。如果我持有这个代理实例并且它进入故障状态,然后我调用 Abort() 并尝试重新初始化它,任一服务将允许/招待该代理实例,因为另一个实例没有在服务端正常关闭?
    • 如果代理处于故障状态,您无能为力。如果您的网络连接丢失怎么办?恕我直言,MaxConcurrentInstances(在 PerCall 场景中)只告诉服务器它一次可能实例化多少个服务对象 - 如果这是一个并且另一个调用来了,调用将只需要等到实例一个完成。
    • 你是对的 MaxConcurrentInstances 只告诉服务器它可以实例化多少个服务对象。如果我错了,请纠正我,代理开始与 Service 通信但没有调用/调用 Close() 方法我假设如果另一个调用到达,Service 将不会同时处理 InstanceContext (和相关资源)将保持等待状态,直到 proxy1 调用 Close() 方法。
    • 这可能取决于代理/调用/INstanceContextMode 的类型,我必须阅读文档或对其进行测试才能确定,但​​我认为服务器对关闭客户端不感兴趣一点也不。在这种情况下(每次调用)与 ASP.NET 几乎相同 - 服务对象在调用时创建,成员被调用,仅此而已。
    • OK Carsten 我也试过测试这个场景,会分享给大家。您能否分享您为发布 Connected 和 Fault 事件而编写的代理的代码,并使用首先尝试关闭代理的代码实现 IDisposable 并且当引发 CommunicationException 时继续 Abort 您在回复中提到或参考任何文章或知识库。这一定对我有益。
    猜你喜欢
    • 2014-11-25
    • 1970-01-01
    • 2021-05-16
    • 2011-06-12
    • 2023-03-03
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多