异常的 WCF 客户端行为

Posted

技术标签:

【中文标题】异常的 WCF 客户端行为【英文标题】:Unusual WCF Client behaviour 【发布时间】:2014-10-19 15:26:30 【问题描述】:

我有一个 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 服务,那么我也可以在这种情况下创建另一个。

**UPDATE 2: ** 单步执行,我可以看到incomingChannel.Close() 没有完成并且没有抛出错误。我删除了该部分,还发现 proxy.Close() 没有完成,也没有抛出异常。我尝试使用重载并添加了超时,但没有引发超时异常。 Service 的 Dispose() 方法根本没有命中。

【问题讨论】:

根据您的症状,我想知道问题是否出在服务代码上,而不是客户端上。您是否调试过服务以查看与客户端的会话是否/何时终止?启动第二个会话时是否会在服务上引发错误? 检查起来很棘手,因为一旦附加了调试器,问题就不会出现。就好像 Visual Studio 弥补了这些问题并硬重启了频道。 does not complete and does not throw an exception 这怎么可能?代码不只是在执行过程中小憩。 好吧,我认为它最终会超时,但它不会抛出任何异常并且添加超时没有任何区别 - 我可以在 5 秒后将关闭设置为超时,但是 20几分钟后,仍然没有任何事情发生。我正在单步执行代码,但从未点击过下一行。 @MrShoes - 启动 WCF 跟踪。这可能会为我们指明正确的方向。参考***.com/questions/4271517/how-to-turn-on-wcf-tracing 【参考方案1】:

也尝试关闭你的频道工厂。

proxy.ChannelFactory.Close();
proxy.Close();

【讨论】:

如果您查看更新 2,您会发现 Close 方法实际上并未完成。

以上是关于异常的 WCF 客户端行为的主要内容,如果未能解决你的问题,请参考以下文章

WCF - 客户端是不是必须具有与端点相同的行为?

从 WCF 4 REST 模板获取调试输出

WCF系列教程之WCF客户端异常处理

WCF 的“使用”语句中的异常未正确关闭连接。如何关闭有故障的 WCF 客户端连接或有异常的连接?

WCF 客户端异常:无法识别的消息版本

WCF 服务奇怪的行为