SignalR 通过 MVC 控制器取得进展
SignalR Progress through MVC Controller
上图表示我正在尝试解决的场景。
根据我以前的经验,我知道进度报告模式可用于解决保持客户端更新的问题,但当时客户端直接与集线器通信,这意味着没有控制器或代码隐藏。
在上图中,问题是控制器在调用数据库之前需要做一些事情。
此外,数据库 returns 以文件的形式分段,所以我添加了一个异步文件系统观察器,用于在每次创建响应文件时通知我。
我们的目标是在您收到响应片段时继续向客户端浏览器提供响应片段,直到我们到达响应末尾。
问题是:如何从控制器/服务方法触发 signalR Hub 并继续向客户端浏览器提供响应?
更新:
缩小问题范围
我的控制器调用服务方法
string contents = await _logService. ResponseFileWaiterAsync (myData.guid.ToString());
在 ResponseFilewaiterAsync
方法中,当创建第一个文件时,我触发了 hub
BroadcastResponseToClient(responseFilePath, hubConnection);
private void BroadcastResponseToClient(string responseFilePath, HubConnection hubConnection)
{
var hub = hubConnection.CreateHubProxy(typeof(string).Name);
hubConnection
.Start()
.ContinueWith(_ => hub.Invoke("UpdateResponseToClient", ResponseHtml));
}
集线器向客户端报告响应并寻找下一个文件直到完成
public async Task UpdateResponseToClient(IProgress<string> progress,string filePath)
{
// Clients.Caller.appendReportToPage(ResponseHtml);
string result = await _jbaseLoggingService.ResponseFileWaiterAsync(filePath);
progress.Report(result);
}
问题:如何从服务方法/控制器触发进度报告中心?
完成更新后,我应该在哪里完成我的请求——它应该返回控制器吗?
我想我可能已经解决了我的问题。我要做的第一件事是渲染一个空的占位符客户端,这样我就可以启动我的客户端连接(集线器连接),然后在将连接 ID 发送到控制器时对实际控制器方法进行 AJAX 调用.
控制器调用服务方法
await _logService.ResponseFileWaiterAsync(myData.guid.ToString(),clientId);
服务等待 filewatcher 通知文件 created/renamed 然后读取文件的内容并借助 clientId
将其传回给客户端
ResponseFileWaiterAsync(string responseFileName, string clientId)
{
//do stuff
await DropFileHelper.WaitForResponseFileAsync(responseFilePath);
contents = LoadResponseFile(responseFilePath);
//do stuff
Clients.Client(clientId).appendReportToPage(contents);
}
使用
在构造函数中加载客户端
Clients = GlobalHost.ConnectionManager.GetHubContext<MyResponseHub>().Clients;
appendReportToPage - 是客户端回调方法
MyResponseHub 是空的。我所需要的只是确保 SignalR 有一个集线器来发挥它的魔力
public class JbaseResponseHub : Hub
{
}
- 客户端 JS
$(function () {
var _clientId;
var hubProxy = $.connection.myResponseHub;
hubProxy.client.appendReportToPage = function (ResponseHtml) {
// Add the message to the page.
$('#responseBody').append( "<p>"+ResponseHtml+"</p>" + '</br></br></br>');
};
$.connection.hub.start()
.done(function () {
//alert('in hub start');
_clientId = $.connection.hub.id;
console.log('Now connected, connection ID=' + $.connection.hub.id);
//alert(_clientId);
$.ajax({
type: 'GET',
url: '/mycontroller/ProcessRequest',
data: { qs: $('#encryptedString').html().trim(), clientId: _clientId },
cache: false,
success: function (result) {
}
});
})
.fail(function(){ console.log('Could not Connect!'); });
});
经验教训
- 必须呈现客户端,以便它可以与集线器建立连接
- 只要您有权访问客户端
,您就可以通过服务class/方法与客户端通信
有用的链接
http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#genproxy
http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc
上图表示我正在尝试解决的场景。
根据我以前的经验,我知道进度报告模式可用于解决保持客户端更新的问题,但当时客户端直接与集线器通信,这意味着没有控制器或代码隐藏。
在上图中,问题是控制器在调用数据库之前需要做一些事情。
此外,数据库 returns 以文件的形式分段,所以我添加了一个异步文件系统观察器,用于在每次创建响应文件时通知我。
我们的目标是在您收到响应片段时继续向客户端浏览器提供响应片段,直到我们到达响应末尾。
问题是:如何从控制器/服务方法触发 signalR Hub 并继续向客户端浏览器提供响应?
更新:
缩小问题范围
我的控制器调用服务方法
string contents = await _logService. ResponseFileWaiterAsync (myData.guid.ToString());
在
ResponseFilewaiterAsync
方法中,当创建第一个文件时,我触发了 hubBroadcastResponseToClient(responseFilePath, hubConnection); private void BroadcastResponseToClient(string responseFilePath, HubConnection hubConnection) { var hub = hubConnection.CreateHubProxy(typeof(string).Name); hubConnection .Start() .ContinueWith(_ => hub.Invoke("UpdateResponseToClient", ResponseHtml)); }
集线器向客户端报告响应并寻找下一个文件直到完成
public async Task UpdateResponseToClient(IProgress<string> progress,string filePath) { // Clients.Caller.appendReportToPage(ResponseHtml); string result = await _jbaseLoggingService.ResponseFileWaiterAsync(filePath); progress.Report(result); }
问题:如何从服务方法/控制器触发进度报告中心? 完成更新后,我应该在哪里完成我的请求——它应该返回控制器吗?
我想我可能已经解决了我的问题。我要做的第一件事是渲染一个空的占位符客户端,这样我就可以启动我的客户端连接(集线器连接),然后在将连接 ID 发送到控制器时对实际控制器方法进行 AJAX 调用.
控制器调用服务方法
await _logService.ResponseFileWaiterAsync(myData.guid.ToString(),clientId);
服务等待 filewatcher 通知文件 created/renamed 然后读取文件的内容并借助 clientId
将其传回给客户端ResponseFileWaiterAsync(string responseFileName, string clientId) { //do stuff await DropFileHelper.WaitForResponseFileAsync(responseFilePath); contents = LoadResponseFile(responseFilePath); //do stuff Clients.Client(clientId).appendReportToPage(contents); }
使用
在构造函数中加载客户端Clients = GlobalHost.ConnectionManager.GetHubContext<MyResponseHub>().Clients;
appendReportToPage - 是客户端回调方法
MyResponseHub 是空的。我所需要的只是确保 SignalR 有一个集线器来发挥它的魔力
public class JbaseResponseHub : Hub { }
- 客户端 JS
$(function () {
var _clientId;
var hubProxy = $.connection.myResponseHub;
hubProxy.client.appendReportToPage = function (ResponseHtml) {
// Add the message to the page.
$('#responseBody').append( "<p>"+ResponseHtml+"</p>" + '</br></br></br>');
};
$.connection.hub.start()
.done(function () {
//alert('in hub start');
_clientId = $.connection.hub.id;
console.log('Now connected, connection ID=' + $.connection.hub.id);
//alert(_clientId);
$.ajax({
type: 'GET',
url: '/mycontroller/ProcessRequest',
data: { qs: $('#encryptedString').html().trim(), clientId: _clientId },
cache: false,
success: function (result) {
}
});
})
.fail(function(){ console.log('Could not Connect!'); });
});
经验教训
- 必须呈现客户端,以便它可以与集线器建立连接
- 只要您有权访问客户端 ,您就可以通过服务class/方法与客户端通信
有用的链接
http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#genproxy http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc