我有一个SOA应用程序,它使用Windows服务中托管的双工WCF服务。客户端本身就是一个WPF应用程序。
我在关闭和重新启动客户端应用程序时看到异常行为。如果我在关闭一个实例后开始一个新实例,那么看起来就不会发生任何事情。但是,检查任务管理器会显示新实例正在作为后台进程运行。如果我尝试启动客户端应用程序的另一个新实例,它将显示我写的错误屏幕 - 说明服务错误。调查显示客户端无法创建服务回调通道的新实例,因为另一个应用程序已经注册了URL。这是一个System.ServiceModel.AddressAlreadyInUseException。
如果我在任务管理器中结束后台客户端任务,则显示错误消息的客户端可以连接到服务并正常运行。我还注意到,如果在开始新实例之前关闭后台任务,新实例也不会出现。
我担心的是,这是不可用的,对用户来说感觉真的很麻烦。怎么可能出错?似乎有些事情没有清理非托管资源,但我已经使用过ANTS并且无法识别它。客户端创建为:
IServiceCallback callback = new Callback();
_context = new InstanceContext(callback);
_channelFactory = new DuplexChannelFactory<IMyService>(_context, binding, endpoint);
_proxy =
_channelFactory.CreateChannel();
((ICommunicationObject)_proxy).Open(TimeSpan.FromSeconds(5));
Service的构造函数使用以下代码:
_callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
var commObject = _callback as ICommunicationObject;
if (commObject != null)
{
commObject.Faulted += ChannelFaulted;
commObject.Closing += ChannelClosing;
commObject.Closed += ChannelClosed;
}
OperationContext.Current.Channel.Faulted += ChannelFaulted;
OperationContext.Current.Channel.Closed += ChannelFaulted;
在关闭之前,客户端调用服务的Disconnect方法,该方法执行:
var commObject = _callback as ICommunicationObject;
if (commObject != null)
{
commObject.Faulted -= ChannelFaulted;
commObject.Closing -= ChannelClosing;
commObject.Closed -= ChannelClosed;
}
OperationContext.Current.Channel.Faulted -= ChannelFaulted;
OperationContext.Current.Channel.Closed -= ChannelFaulted;
最后,客户关闭这样的渠道:
foreach (var incomingChannel in _context.IncomingChannels.ToArray())
{
incomingChannel.Close();
}
try
{
var proxy = _proxy as IChannel;
if (proxy != null)
{
proxy.Close();
}
}
catch (Exception)
{
_channelFactory.Abort();
}
为什么我会看到这种不寻常的行为?是否有一些我想要关闭频道的东西或者我做错了什么?或者是否可能在我的代码中的其他地方一直存在使通道或会话保持活动的问题?
**更新:**我一直在尝试一些事情,并发现如果我启动一个客户端实例,关闭它,然后保持一个小时,我可以启动另一个没有问题的实例。我还发现,如果在创建和关闭客户端应用程序实例后重新启动Windows服务,那么我也可以在这些情况下创建另一个。
**更新2:**单步执行,我可以看到incomingChannel.Close()没有完成,也没有抛出错误。我删除了该部分,并且还发现proxy.Close()没有完成,也没有抛出异常。我尝试使用重载并添加了超时,但没有抛出超时异常。服务的Dispose()方法根本没有被击中。
答案 0 :(得分:1)
尝试关闭您的频道工厂。
proxy.ChannelFactory.Close();
proxy.Close();