通道超时 - 在代理中重用和处置 WCF 通道

问题描述

在许多 SOF 主题中,人们正在讨论如何以正确的方式处理 Channels 或 ChannelFactories。
因此,我确实很好地掌握了这里应该做什么。
但是,我的系统有点不合常规,因为代理客户端的实现没有提供给用户
换句话说,如果有人想要创建一个需要与我的服务通信的应用程序,它必须使用提供的代理 dll 来完成。

现在,这个代理 dll 是创建通道工厂和通道的那个。到现在为止还挺好。我的基类是缓存工厂的一个(为了简单起见,这里没有提供缓存),因此它只在构造时实例化一次。

我遇到的问题是这些代理公开了许多方法,每个方法都需要使用一个通道才能与服务进行通信。
然而,我更希望在每次方法调用时都创建一个新通道,而不是让同一个通道永远保持活动状态(这是我目前所做的,而且很糟糕!)。

所以这是我目前所拥有的:

负责创建通道工厂的基类:

public abstract class MyProxyBase<T> : IMyProxyBase,Idisposable
{
    protected dynamic _channel { get; set; }

    protected DuplexChannelFactory<T> _channelFactory = default;

    protected readonly object _locker = new object();

    public T CreateChannelFactory(string serviceName)
    {
        lock (_locker)
        {
            var ctx = new InstanceContext(DeviceManagerCallbackProxy.Instance);

            string baseAddress = Constants.ServiceBaseAddress;

            if (string.IsNullOrEmpty(serviceName))
                serviceName = Constants.DefaultServiceName;
                
            switch (typeof(T).Name)
            {

                case nameof(ISomeService1):
                    baseAddress += "1/";
                    break;

                case nameof(ISomeService2):
                    baseAddress += "2/";
                    break;

                default:
                    throw new SystemException();
            }
                

            var binding = new NetNamedPipeBinding(); // (serviceName);
            binding.MaxConnections = 10;
            binding.OpenTimeout = System.TimeSpan.FromMinutes(1);
            binding.CloseTimeout = System.TimeSpan.FromMinutes(1);
            binding.ReceiveTimeout = System.TimeSpan.FromMinutes(5);
            binding.SendTimeout = System.TimeSpan.FromMinutes(5);

            _channelFactory = new DuplexChannelFactory<T>(ctx,binding,new EndpointAddress(baseAddress + serviceName));

            // Create channel to a specified endpoint
            // !!! I probably should not be creating a channel at this stage - But only when needed instead!
            _channel = _channelFactory.CreateChannel();

            return _channel;
        }
    }
    
    public void dispose()
    {
        if (_channelFactory != null)
        {
            if (_channelFactory.State == CommunicationState.Opened)
            {
                try
                {
                    // Try to close the channel normally
                    _channelFactory.Close();
                }
                catch (TimeoutException)
                {
                    // Handle the timeout exception
                    _channelFactory.Abort();
                }
                catch (CommunicationException)
                {
                    // Handle the communication exception
                    _channelFactory.Abort();
                }
            }
        }
    }
}

要编译并作为 dll 提供给客户的给定代理:

public class MyProxyX : MyProxyBase<ISomeService1>,IMyProxyX
{
    // Constructor
    public MyProxyX (string serviceName)
    {
        // Get Channel out of new Channel Factory
        _channel = CreateChannelFactory(serviceName);

    }

    // Some methods using the channel
    public bool DoSomething()
    {

       return _channel?.DoSomething();
    }

    // There are many other methods of the type
    // ....
}

所以现在,考虑到用户在使用这个 dll 时唯一会看到的是 Proxy 的公共方法,我希望从 Proxy 类中正确处理/处置通道。

也许这样做的一个方法是每次在 MyProxyX() 中调用方法时总是创建一个新通道。
意思是不是做 _channel.?DoSomething(),我们可以做一些类似的事情(但是我怎样才能确保以前的频道被正确地垃圾收集?):

// Create a new Channel instead of using _channel
protected SomeService1 MyCurrentChannel 
{
    get { return _channelFactory.CreateChannel(); }
}

最后以这种方式实现了 DoSomething():

public bool DoSomething()
{    
   return MyCurrentChannel?.DoSomething();
}

但是我不想在每次方法调用后都手动处理通道。换句话说,为每个方法做以下事情将是丑陋的:

public bool DoSomething()
{    
   bool pass = MyCurrentChannel?.DoSomething();
   MyCurrentChannel.dispose();
   return pass;
}

protected virtual void dispose(bool disposing)
{
    try
    {
        (MyCurrentChannel as ICommunicationObject).Close();
    }
    catch (CommunicationException)
    {
        (MyCurrentChannel as ICommunicationObject).Abort();
    }
    catch (TimeoutException)
    {
        (MyCurrentChannel as ICommunicationObject).Abort();
    }
}

public void dispose()
{
    dispose(true);
}

对此的任何帮助将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)