Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WCF双工通道:检查回调通道是否仍然可用_Wcf_Client_Duplex Channel - Fatal编程技术网

WCF双工通道:检查回调通道是否仍然可用

WCF双工通道:检查回调通道是否仍然可用,wcf,client,duplex-channel,Wcf,Client,Duplex Channel,我有以下问题。我在写聊天软件。客户机/服务器机制基于WCF的DualHttpBinding。这意味着,如果用户发送消息,服务器将通知发送消息的房间中的所有客户端 我想确保,如果客户机的应用程序崩溃(无论是什么原因),客户机对象将从文件室列表中删除 在调用回调操作之前,是否可以检查回调通道的状态?问题是,如果我在不再连接的客户机上调用操作(由于意外崩溃),服务将挂起 public YagzResult SendMessage(Message message) { fore

我有以下问题。我在写聊天软件。客户机/服务器机制基于WCF的DualHttpBinding。这意味着,如果用户发送消息,服务器将通知发送消息的房间中的所有客户端

我想确保,如果客户机的应用程序崩溃(无论是什么原因),客户机对象将从文件室列表中删除

在调用回调操作之前,是否可以检查回调通道的状态?问题是,如果我在不再连接的客户机上调用操作(由于意外崩溃),服务将挂起

 public YagzResult SendMessage(Message message)
    {
        foreach (ChatNodeAddress chatNodeAddress in message.Destination)
        {
            ChatNode chatNode = chatProvider.FindChatNode(chatNodeAddress);
            if (chatNode != null)
            {
                User currentUser = CurrentUser;
                foreach (User user in chatNode)
                {
                    //Don't notify the current client. Deadlock!
                    if (!user.Equals(currentUser))
                    {
                        //Get the callback channel here
                        IYagzClient client = GetClientByUser(user);

                        if (client != null)
                        {
                            //--> If the client here called is not any more available,
                            //the service will hang <---
                            client.OnChatMessageReceived(message);
                        }
                    }
                }
            }
            else
            {
                return YagzResult.ChatNodeNotFound;
            }
        }
        return YagzResult.Ok;
    }
公共YagzResult发送消息(消息消息) { foreach(message.Destination中的chatnodeddress chatnodeddress) { ChatNode ChatNode=chatProvider.FindChatNode(chatnodeddress); if(chatNode!=null) { 用户当前用户=当前用户; foreach(chatNode中的用户) { //不要通知当前客户端。死锁! 如果(!user.Equals(currentUser)) { //在这里获取回调通道 IYagzClient=GetClientByUser(用户); 如果(客户端!=null) { //-->如果这里调用的客户端不再可用,
//该服务将挂起已关闭和出现故障的通信对象(即回调通道)上存在事件。您可能希望为这些事件添加处理程序,并跟踪哪些客户端仍有可用的有效通道


您还可以查看IChannelInitializer类,以实现对客户端的跟踪。

主要问题是,除了a之外,我没有收到任何异常。我的服务被阻止了1分钟(我设置的超时),直到触发异常

我通过以下解决方法解决了这个问题。我没有在服务的当前工作线程上调用客户端回调操作,而是创建了一个新线程,该线程调用客户端回调操作并等待TimeoutException。如果发生超时,用户只需从他所属的聊天室列表中删除

这是一段代码片段,展示了我是如何做到这一点的:

首先,我创建了一个类,表示对客户端的单个调用:

class YagzClientAsyncCall<T>
{
    /// <summary> Gets or sets the parameter of the client callback. </summary>
    /// <value> The parameter. </value>
    T Param { get; set; }

    /// <summary> Gets or sets the client. </summary>
    /// <value> The client. </value>
    IYagzClient Client { get; set; }

    /// <summary> Gets or sets the service. </summary>
    /// <value> The service. </value>
    YagzService Service { get; set; }

    /// <summary> Constructor. </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="service"> The service. </param>
    /// <param name="client">  The client. </param>
    /// <param name="param">   The parameter. </param>
    public YagzClientAsyncCall(YagzService service, IYagzClient client, T param)
    {
        Param = param;
        Client = client;
    }

    /// <summary>   
    /// Invokes the client callback. If a timeout exception occurs, 
    /// the client will be removed from clients' list.
    /// </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="clientCallback">   The client callback. </param>
    protected void Invoke(Action<T> clientCallback)
    {
        try
        {
            if (clientCallback != null)
            {
                clientCallback(Param);
            }
        }
        catch (TimeoutException)
        {
            // Remove the client and the user
            Service.RemoveClient(Client);
        }
    }

    protected void Invoke(object objCallback)
    {
        Invoke(objCallback as Action<T>);
    }

    public void CallOperationAsync(Action<T> clientCallback)
    {
        ParameterizedThreadStart ts = new ParameterizedThreadStart(this.Invoke);
        Thread t = new Thread(ts);
        t.Start(clientCallback);
    }
}
类YagzClientAsyncCall { ///获取或设置客户端回调的参数。 ///参数。 T参数{get;set;} ///获取或设置客户端。 ///客户。 IYagzClient客户机{get;set;} ///获取或设置服务。 ///服务。 YagzService服务{get;set;} ///构造器。 ///西蒙,30.12.2009。 ///服务。 ///客户。 ///参数。 公共YAGZClient同步调用(YagzService服务、IYagzClient客户端、T参数) { Param=Param; 客户=客户; } /// ///调用客户端回调。如果发生超时异常, ///客户端将从客户端列表中删除。 /// ///西蒙,30.12.2009。 ///客户端回调。 受保护的无效调用(操作clientCallback) { 尝试 { if(clientCallback!=null) { clientCallback(Param); } } 捕获(超时异常) { //删除客户端和用户 服务。RemoveClient(客户); } } 受保护的void调用(对象objCallback) { 调用(objCallback作为操作); } public void CallOperationAsync(Action clientCallback) { ParameterizedThreadStart ts=新的ParameterizedThreadStart(this.Invoke); 螺纹t=新螺纹(ts); t、 启动(clientCallback); } } 假设以下代码是通知聊天室客户端已写入新消息的方法的一部分:

foreach (User user in chatNode)
{
     // Don't notify the current client. Deadlock!
     if (!user.Equals(currentUser))
     {
         IYagzClient client = GetClientByUser(user);

         if (client != null)
         {
             var asyncCall = new YagzClientAsyncCall<Message>(this, client, message);
             asyncCall.CallOperationAsync(client.OnChatMessageReceived);
         }
     }
 }
foreach(chatNode中的用户)
{
//不要通知当前客户端。死锁!
如果(!user.Equals(currentUser))
{
IYagzClient=GetClientByUser(用户);
如果(客户端!=null)
{
var asyncCall=new YagzClientAsyncCall(此,客户端,消息);
asyncCall.CallOperationAsync(client.OnChatMessageReceived);
}
}
}

我只是创建了一个新的YagzClientAsyncCall对象,并允许在一个新线程上调用该操作。

您可以将回调协定强制转换为,然后检查通道状态。

虽然这可能会起作用,但按需创建这样的线程通常是不好的做法。您可能最终会有1000个不需要的线程。最好使用bocking collection从中读取的固定线程数较少。