如何:响应可用的Wcf双工通信

时间:2021-02-02 19:43:06

I'm working on an application that uses WCF to communicate between server and clients Server has changing number of services, along with one master service that clients can query for information about other services, and then subscribe to those they want using information from master service.

我正在开发一个使用WCF在服务器和客户端之间进行通信的应用程序服务器具有不断变化的服务数量,以及客户端可以查询其他服务信息的一个主服务,然后使用来自主服务的信息订阅他们想要的服务。

Master service sends notifications to subscribed clients, when sub-services change (added, removed, etc) Also sub-services send notifications every few seconds.

当子服务改变(添加,删除等)时,主服务向订阅的客户端发送通知。此外,子服务每隔几秒发送一次通知。

This sounds like a great opportunity for using WCFs Callback channels, however, they require you to use session. Also when sending notifications to clients, when any of the cliens got disconnected disgracefully the service hangs, trying to notify it. Even if it times out, after some time, during that time no other client get's notified and this is not acceptable, since the clients are actually GUIs for monotoring applications behind sub-services. Also using MSMQ for that is not an option, since the service needs to know immediatelly, when send operation did not succeed.

这听起来像是使用WCF回调频道的绝佳机会,但是,它们要求您使用会话。此外,当向客户端发送通知时,当任何一个客户断断续续地断开连接时,服务会挂起,尝试通知它。即使它超时,经过一段时间,在此期间没有其他客户端得到通知,这是不可接受的,因为客户端实际上是用于监视子服务背后的应用程序的GUI。此外,使用MSMQ也不是一个选项,因为当发送操作没有成功时,服务需要立即知道。

The solution I came up with is using http binding (to know immediatelly when send did not succeed) and creating explicit callback services on the client, but that requires me to write a lot of ugly looking infrastructore code.

我想出的解决方案是使用http绑定(在发送失败时立即知道)并在客户端上创建显式回调服务,但这需要我编写许多丑陋的基础架构代码。

So, my question is: is there a better way of doing this with WCF. The best looking option was Callback Contracts, because that frees me from needing to manage callback service manually, if only it could not wait for ack from one client before trying to send to the next one.

所以,我的问题是:有没有更好的方法与WCF这样做。最好看的选项是Callback Contracts,因为这使我无需手动管理回调服务,只要它在尝试发送到下一个客户端之前无法等待来自一个客户端的ack。

1 个解决方案

#1


3  

I have a similar environment (without the dynamic services) and had a very similar issue when client channels faulted. The first solution I came up with was to wrap the callbacks in try/catch statements and remove the offending client if something went wrong but this had issues and didn't look like it would scale at all.

我有一个类似的环境(没有动态服务),并在客户端通道出现故障时遇到类似的问题。我想出的第一个解决方案是将回调包装在try / catch语句中,如果出现问题就删除有问题的客户端,但这有问题,看起来根本不会扩展。

The solution I ended up going with was to use a delegated event handler and to call it using BeginInvoke. If you haven't looked at the CodeProject: WCF/WPF Chat Application (Chatters) solution, I recommend checking it out.

我最终使用的解决方案是使用委托事件处理程序并使用BeginInvoke调用它。如果您还没有查看CodeProject:WCF / WPF聊天应用程序(Chatters)解决方案,我建议您查看它。

When a user logs in, an event handler is created and added to the main event:

当用户登录时,会创建一个事件处理程序并将其添加到主事件中:

public bool Login() 
{
    ...
    _myEventHandler = new ChatEventHandler(MyEventHandler);
    ChatEvent += _myEventHandler;
    ...
}

Whenever a message needs to be broadcast, the event handlers are called asynchronously:

每当需要广播消息时,异步调用事件处理程序:

private void BroadcastMessage(ChatEventArgs e)
{
    ChatEventHandler temp = ChatEvent;
    if (temp != null)
    {
        foreach (ChatEventHandler handler in temp.GetInvocationList())
        {
            handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
        }
    }
}

When the returns come back, the result is handled and if something bad happened the event handler for that channel is removed:

当返回返回时,将处理结果,如果发生了错误,则删除该通道的事件处理程序:

private void EndAsync(IAsyncResult ar)
{
    ChatEventHandler d = null;
    try
    {
        //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then
        //cast it to the correct delegate type, and do an end invoke
        System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
        d = ((ChatEventHandler)asres.AsyncDelegate);
        d.EndInvoke(ar);
    }
    catch(Exception ex)
    {
        ChatEvent -= d;
    }
}

The code above is modified (slightly) from the WCF/WPF Chat Application posted by Sacha Barber.

从Sacha Barber发布的WCF / WPF聊天应用程序(稍微)修改上面的代码。

#1


3  

I have a similar environment (without the dynamic services) and had a very similar issue when client channels faulted. The first solution I came up with was to wrap the callbacks in try/catch statements and remove the offending client if something went wrong but this had issues and didn't look like it would scale at all.

我有一个类似的环境(没有动态服务),并在客户端通道出现故障时遇到类似的问题。我想出的第一个解决方案是将回调包装在try / catch语句中,如果出现问题就删除有问题的客户端,但这有问题,看起来根本不会扩展。

The solution I ended up going with was to use a delegated event handler and to call it using BeginInvoke. If you haven't looked at the CodeProject: WCF/WPF Chat Application (Chatters) solution, I recommend checking it out.

我最终使用的解决方案是使用委托事件处理程序并使用BeginInvoke调用它。如果您还没有查看CodeProject:WCF / WPF聊天应用程序(Chatters)解决方案,我建议您查看它。

When a user logs in, an event handler is created and added to the main event:

当用户登录时,会创建一个事件处理程序并将其添加到主事件中:

public bool Login() 
{
    ...
    _myEventHandler = new ChatEventHandler(MyEventHandler);
    ChatEvent += _myEventHandler;
    ...
}

Whenever a message needs to be broadcast, the event handlers are called asynchronously:

每当需要广播消息时,异步调用事件处理程序:

private void BroadcastMessage(ChatEventArgs e)
{
    ChatEventHandler temp = ChatEvent;
    if (temp != null)
    {
        foreach (ChatEventHandler handler in temp.GetInvocationList())
        {
            handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
        }
    }
}

When the returns come back, the result is handled and if something bad happened the event handler for that channel is removed:

当返回返回时,将处理结果,如果发生了错误,则删除该通道的事件处理程序:

private void EndAsync(IAsyncResult ar)
{
    ChatEventHandler d = null;
    try
    {
        //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then
        //cast it to the correct delegate type, and do an end invoke
        System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
        d = ((ChatEventHandler)asres.AsyncDelegate);
        d.EndInvoke(ar);
    }
    catch(Exception ex)
    {
        ChatEvent -= d;
    }
}

The code above is modified (slightly) from the WCF/WPF Chat Application posted by Sacha Barber.

从Sacha Barber发布的WCF / WPF聊天应用程序(稍微)修改上面的代码。