如何解决通道超时 - 在代理中重用和处置 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 举报,一经查实,本站将立刻删除。