如何使用 SignalR 从 ASP.NET MVC 3 通知 Web 客户端 MSMQ 任务已完成

Posted

技术标签:

【中文标题】如何使用 SignalR 从 ASP.NET MVC 3 通知 Web 客户端 MSMQ 任务已完成【英文标题】:How to use SignalR to notify web clients from ASP.NET MVC 3 that MSMQ tasks were completed 【发布时间】:2011-12-31 19:22:41 【问题描述】:

如何使用 SignalR 在 .NET 4.0 系统中实现通知,该系统由 ASP.NET MVC 3 应用程序(使用表单身份验证)、SQL Server 2008 数据库和 MSMQ WCF 服务(托管在 WAS 中)来处理数据?运行时环境由在 Windows Server 2008 R2 标准版上运行的 IIS 7.5 组成。

我只玩过样本,对 SignalR 的知识并不丰富。

这里有一些背景

Web 应用程序接受来自用户的数据并将其添加到表中。然后它调用 WCF 服务的单向操作(使用数据库键)来处理数据(任务)。 Web 应用程序返回到一个页面,告诉用户数据已提交,处理完成后将通知他们。用户可以查看“索引”页面以查看哪些任务已完成、失败或正在进行中。他们可以继续提交更多的任务(这与之前的数据无关)。他们可以关闭浏览器,稍后再回来。

基于 MSMQ 的 WCF 服务从数据库中读取记录并处理数据。这可能需要几毫秒到几分钟的时间。处理完数据后,记录会更新相应的状态(错误或失败)和结果。

大多数时候,WCF 服务不执行任何处理,但是当它执行时,用户通常希望尽快知道它何时完成。用户仍然会使用 Web 应用程序的其他部分,即使他们没有要由 WCF 服务处理的数据。

这就是我所做的

在主导航栏中,我有一个指示器(类似于 Facebook 或 Google+)供用户在任务状态发生变化时通知他们。当他们点击它时,他们会获得所做工作的摘要,然后可以根据需要查看结果。

使用 jQuery,我轮询服务器以获取更改。控制器操作检查是否有任何进程被修改(完成或失败)并返回它们,否则等待几秒钟并再次检查而不返回客户端。为了避免客户端超时,如果没有更改,它将在 30 秒后返回。 jQuery 脚本等待一段时间并再次尝试。

问题

每个查看页面的用户都会降低性能。他们不需要做任何特别的事情。我们注意到 Firefox 7+ 和 Safari 的内存使用量随着时间的推移而增加。

使用 SignalR

我希望切换到 SignalR 可以减少轮询,从而减少资源需求,特别是如果数据库中的任务方面没有任何改变。我很难让 WCF 服务通知客户端它已完成处理任务,因为它使用基于表单的身份验证。

通过提出这个问题,我希望有人能让我更好地了解他们将如何使用 SignalR 重新设计我的通知方案(如果有的话)。

【问题讨论】:

对this的任何建议 【参考方案1】:

如果我理解正确,您需要一种将任务与给定用户/客户相关联的方法,以便您可以在他们的任务完成时告诉客户。

SignalR API 文档告诉我,您可以根据客户端 ID (https://github.com/SignalR/SignalR/wiki/SignalR-Client) 为特定客户端调用 JS 方法。理论上你可以这样做:

    将 SignalR 使用的客户端 ID 存储为任务元数据的一部分: 正常排队任务。 当任务被处理和出队时: 使用状态更新您的数据库。 使用作为该任务的一部分存储的客户端 ID,使用 SignalR 向该客户端发送通知:

您应该能够检索您的客户端正在使用的连接并向他们发送消息:

string clientId = processedMessage.ClientId //Stored when you originally queued it.
IConnection connection = Connection.GetConnection<ProcessNotificationsConnection>();
connection.Send(clientId, "Your data was processed");

这假设您映射了此连接,并且客户端首先使用该连接来启动数据处理请求。您的“主导航栏”具有启动与您之前映射的 ProcessNotificationsConnection 端点的连接的 JS。

编辑:来自https://github.com/SignalR/SignalR/wiki/Hubs

public class MyHub : Hub

     public void Send(string data)
     
     // Invoke a method on the calling client
     Caller.addMessage(data);

     // Similar to above, the more verbose way
     Clients[Context.ClientId].addMessage(data);

     // Invoke addMessage on all clients in group foo
     Clients["foo"].addMessage(data);
     

【讨论】:

非 JS 客户端 API 不允许我向特定组或客户端发送消息。结果,将其发送到后台进程没有任何价值。但是,我确实将 id 发送回网站,然后获取“所有者”的“id”并使用该“id”向 SignalR 组发送通知。当用户连接和断开连接时,我将客户端添加到组中。 您的回答有效,但是,最后我决定放弃 SignalR 以获得透明支持安全性的自定义解决方案。因此,用户只能向有权查看此类消息的用户发送通知。该要求从来不是原始问题的一部分,因此我将您的要求标记为答案。 @WernerStrydom 您是选择了不同的库还是从头开始编写所有代码?您能否进一步说明您的最终实现? 我正在使用长轮询。许多浏览器都禁用了 html5 套接字,因此其他机制(例如 flash)有很多限制。 没问题。很好,你做了你的尽职调查。 SignalR 将继续改进,希望您以后可以再次查看它:)。

以上是关于如何使用 SignalR 从 ASP.NET MVC 3 通知 Web 客户端 MSMQ 任务已完成的主要内容,如果未能解决你的问题,请参考以下文章

《ASP.NET SignalR系列》第二课 SignalR的使用说明

[Asp.net 开发系列之SignalR篇]专题二:使用SignalR实现酷炫端对端聊天功能

发现 ASP.NET Core SignalR

《ASP.NET SignalR系列》第一课 认识SignalR

Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

ASP.NET Core的实时库: SignalR -- 预备知识