1

我最近开始编写自己的 ChannelFactory 包装器来调用我的 WCF 服务,而不是依赖于 Visual Studio 自动生成的代码

以前,使用自动生成的代理,我可以这样做以进行错误检查:

    protected AccessControlServiceClient AccessControlService
    {
        get
        {
            // Check if not initialized yet
            if (HttpContext.Current.Session["AccessControlServiceClient"] == null)
                HttpContext.Current.Session["AccessControlServiceClient"] = new AccessControlServiceClient();

            // If current client is 'faulted' (due to some error), create a new instance.
            var client = HttpContext.Current.Session["AccessControlServiceClient"] as AccessControlServiceClient;
            if (client.State == CommunicationState.Faulted)
            {
                try { client.Abort(); }
                catch { /* no action */ }

                client = new AccessControlServiceClient();
                HttpContext.Current.Session["AccessControlServiceClient"] = client;
            }

            return client;
        }
    }

我应该如何为 ChannelFactor 处理这个问题?如果出现问题,处理和重新创建频道的最佳做法是什么?例如,间歇性网络连接、会话超时等。

这是我的代码目前的样子:

来自 ProxyBase.cs 的片段 - 创建通道

private void Initialise()
{
    lock (_sync)
    {
        if (_channel != null) return;

        _channel = new ChannelFactory<T>(_serviceEndPointUri).CreateChannel();
    }
 }

UserManagementServiceClient.cs - IUserManagementService 是 WCF 合同

public class UserManagementServiceClient : ProxyBase<IUserManagementService>
{
    public UserManagementServiceClient(string serviceEndPointUri)
        : base(serviceEndPointUri)
    {
    }

    public TokenResponse GetToken(TokenRequest request)
    {            
        return Channel.GetToken(request);
    }


    public LoginResponse Login(LoginRequest request)
    {
        return Channel.Login(request);
    }


    public LogoutResponse Logout(LogoutRequest request)
    {
        return Channel.Logout(request);
    }
}

最后,这就是我在 MVC 项目中的调用方式

    protected UserManagementServiceClient UserManagementService
    {
        get
        {
            // Check if not initialized yet
            if (HttpContext.Current.Session["UserManagementServiceClient"] == null)
                HttpContext.Current.Session["UserManagementServiceClient"] = new UserManagementServiceClient("NetTcpBinding_UserManagementService");

            var client = HttpContext.Current.Session["UserManagementServiceClient"] as UserManagementServiceClient;

            return client;
        }
    }

所以目前,每当默认的 10 分钟会话结束时,我都会收到错误消息,因为通道已经关闭。

如何强化我的代码,以便处理网络断开/会话超时等问题?

4

3 回答 3

1

我使用这样的代码

public T Channel {
    get {
        lock (_channelLock) {
            if (!object.Equals(_channel, default(T))) {
                if (((ICommunicationObject)_channel).State == CommunicationState.Faulted) {
                    // channel has been faulted, we want to create a new one so clear it
                    _channel = default(T);
                }
            }

            if (object.Equals(_channel, default(T))) {
                // channel is null, create a new one
                Debug.Assert(_channelFactory != null);
                _channel = _channelFactory.CreateChannel();
            }
            return _channel;
        }
   }
于 2012-11-16T09:11:24.540 回答
1

我通常在每个操作中使用一个新的服务实例。像这样:

public async Task<bool> IsOnline()
    {
        using (var service = new DebugService())
        {
            return await service.OnlineCheckAsync();
        }
    }

除其他外,我的包装器在本文之后实现了 IDisposable 。这样您就不必担心每次执行操作时通道是否出现故障。

编辑

IDisposable 实现的原始链接已损坏,但代码如下所示:

public void Dispose()
    {
        // The following code is from: http://www.vasylevskyi.com/2010/11/correct-wcf-client-proxy-closing.html
        try
        {
            if (this.State != CommunicationState.Closed && this.State != CommunicationState.Faulted)
            {
                ((ICommunicationObject)this).BeginClose(
                    (asr) =>
                    {
                        try
                        {
                            ((ICommunicationObject)this).EndClose(asr);
                        }
                        catch
                        {
                            this.Abort();
                        }
                    }, null
                );
            }
            else
            {
                this.Abort();
            }
        }
        catch (CommunicationException)
        {
            this.Abort();
        }
于 2012-11-19T20:10:21.033 回答
0

在我当前的项目中,我为客户端创建了一个包装类,它使用CurrentInstance访问器模型。在这种情况下,getter 检查_client.State或创建一个新客户端。创建新客户端是由提供给包装器构造函数的工厂委托完成的,因此有一种免费但一致的方式来创建客户端实例。ClosingClosedFaulted

对于您的场景,这意味着将包装器存储在Session而不是直接存储客户端。wrapper.CurrentInstance如果在此期间发生超时,调用将检查状态并在后台重新创建客户端。

该模型还可以通过强大的错误处理(物理断开连接、服务器崩溃......)、延迟初始化、创建新客户端后的任意初始化逻辑(在我的情况下它调用某种Subscribe创建回调通道的方法,但是它可以是任何东西)

我希望这对你来说也是正确的方向。

于 2012-11-16T08:13:06.093 回答