使用Signalr更新列表

时间:2015-01-05 19:12:01

标签: c# signalr

我正在编写一个信号器客户端 - 服务器应用程序。

服务器维护一个项目列表。

客户端显示列表,并允许用户将项目添加到列表中。

假设服务器有一个GetList方法,它返回整个列表,客户端只要客户端将一个项目添加到列表中,就会调用服务器调用的NewItem方法。

这是客户端代码:

public void Init()
{
    hubConnection = new HubConnection(url);
    proxy = hubConnection.CreateHubProxy(hubName);
    proxy.On<String>("NewItem", OnNewItem);
    hubConnection.Start();
    list = proxy.Invoke("GetList");
}

private void OnNewItem(string item)
{
   list.Add(item);
}

我担心以下情况:

  1. 客户端A已连接
  2. 客户端B连接到服务器
  3. 客户端A向列表添加项目,同时客户端B发送GetList消息以获取列表
  4. 此时服务器中有2个线程。线程A正在添加一个项目,然后使用新项目向客户端发送事件。线程B正在加载列表并将其发送回客户端B.

    假设线程B在线程A添加新项目之前从db加载了列表。然后有一个上下文切换,线程A添加了该项,并向所有客户端发送了带有新项的消息。

    现在,线程B恢复并将列表(没有新项目)发送给客户端B.

    从客户B的角度来看,它有一个新项目的事件,他不知道该怎么做,然后它得到了列表但没有新项目。

    客户端B可以忽略新项目消息(因为它在列表初始化之前出现),但随后他将总是丢失1个项目,因为服务器永远不会为此项目发送另一个事件。

    B还可以将消息添加到空列表中,然后添加它获得的列表。但是,如果客户A没有添加项目但删除了一项,该怎么办?在初始化列表之前,B如何处理删除项事件?

1 个答案:

答案 0 :(得分:1)

您尝试做的事情听起来有些困难,特别是如果您允许多个客户端同时任意编辑列表。如果是这种情况,您将考虑实施operational transformation algorithm。虽然这已被广泛研究,但它远非微不足道。

如果您只是尝试订阅由单个来源进行的编辑,则更容易处理。您可以利用这一事实,即您将订阅await hubConnection.Start();完成后发送的任何更新。

这意味着只要您正确{{}},客户端OnNewItem回调将在客户端调用“GetList”期间或之后对“NewItem”进行的任何服务器端调用{1}}在尝试调用“GetList”之前调用await

您在hubConnection.Start()中收到的项目仍然可以复制到“GetList”的回复。要解决此问题,您可以将添加到列表中的每个项目添加一个单调递增的ID,并将其与项目本身一起传递给OnNewItem回调。 “GetList”响应还应包括其最近添加的项目的ID。

在收到对“GetList”的回复之前,您会将OnNewItem中收到的所有项目保留在临时列表中。获得对“GetList”的响应后,您可以添加临时列表中的任何项目,其ID大于添加到“GetList”响应中的最新项目的ID。您忽略ID小于或等于“GetList”响应中返回的ID的任何项目。