【问题标题】:WCF CommunicationException When Subscribed Clients Abort Abnormally订阅客户端异常中止时出现 WCF CommunicationException
【发布时间】:2014-01-27 22:36:40
【问题描述】:

在 WCF 发布/订阅设置中,我目前有一个 Unsubscribe() 方法可以在客户端关闭或需要停止侦听时优雅地断开客户端与 WCF 主机的连接;但是,这不处理客户端强制或异常中止的情况,例如计算机本身断电。如果客户端应用程序以这种方式死掉,那么它的通道仍然存在,并且在发布者下次尝试发送消息时会收到以下错误:

ExceptionDetail> was caught
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted.

客户端匿名订阅,发布者遵循多播结构(任何订阅的客户端/频道都应该收到消息)。虽然我能够捕捉到异常,但我不知道如何从代码中的这一点挑出故障通道,以便处理它并允许其他客户端继续接收消息。我的发布代码类似于以下内容:

public static void Publish(DateTime sendTimeStamp, DataTable sendTable)
        {
            InstanceContext context = new InstanceContext(null, new PublishStatus());
            MessagesClient publishingClient = new MessagesClient(context);
            try {
                publishingClient.PublishMessage(sendTimeStamp, sendTable);

                if (publishingClient.State != CommunicationState.Faulted)
                    publishingClient.Close();
                else
                    publishingClient.Abort();
            }
            catch (CommunicationException ex)
            {
                // This is where the error is caught  
            }
            catch (TimeoutException ex)
            {

                publishingClient.Abort();
            }
            catch (Exception ex)
            {
                publishingClient.Abort();
                throw ex;
            }
        }

是否可以从这一点(异常首先出现在问题上)隔离故障通道并将其处理掉,以便发布服务本身可以继续发送消息?

【问题讨论】:

  • 我真的无法理解,因为我看到你在谈论服务器,但你提供的代码看起来很像客户端的代码。还是我误会了什么?
  • 代码来自发布者(Windows 服务),该发布者会定期向客户端发送消息,客户端订阅并收听消息。你是对的,很多这种异常代码通常也会在客户端,如果它要传回消息的话。设法找到解决方案,但感谢您的时间。 =)

标签: c# wcf publish-subscribe


【解决方案1】:

经过反复试验以及异常研究,我的 WCF 主机中的一个额外的 try-catch 块能够取消订阅错误中止的客户端,并防止错误返回到发布服务。在这里发布一个简单的版本,以防其他人偶然发现相同类型的问题:

public static event MessageEventHandler MessageEvent;
        public delegate void MessageEventHandler(object sender, ServiceEventArgs e);

        IClientContract callback = null;
        MessageEventHandler messageHandler = null;

        public void Subscribe()
        {
            callback = OperationContext.Current.GetCallbackChannel<IClientContract>();
            messageHandler = new MessageEventHandler(Publish_NewMessageEvent);
            MessageEvent += messageHandler;
        }

        public void Unsubscribe()
        {
            MessageEvent -= messageHandler;
        }

        public void PublishMessage(DateTime timeStamp, DataTable table)
        {
            ServiceEventArgs se = new ServiceEventArgs();
            se.timeStamp = timeStamp;
            se.table = table;
            MessageEvent(this, se);
        }

        public void Publish_NewMessageEvent(object sender, ServiceEventArgs e)
        {
            try
            {
                // This callback was causing the error, as the client would no longer exist but the channel would still be open and trying to receive the message
                callback.ReceiveMessage(e.timeStamp, e.table);
            }
            catch
            {
                // Unsubscribe the dead client.
                Unsubscribe();
            }
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多