摘要:
我不确定是否有可能让中心枢纽生活在WCF SignalR服务上。最好让MVC项目充当客户端和Web服务之间的代理。如果这是您的要求之一,您可以稍后使用其他客户端(例如桌面客户端)连接到SignalR,并从您的Web服务连接到此中心枢纽以向指定组中的客户端和/或用户发送更新。
工作流程:
首先,流程看起来更像这样:
![SignalR Workflow](https://istack.dev59.com/vofnZ.webp)
管理客户端连接:
如果您正在使用内存中的方法来管理已连接的用户,则可以通过将连接 ID 和用户 ID 添加到您正在使用的集合中来开始处理此问题。例如:
public static ConcurrentDictionary<String, String> UsersOnline = new ConcurrentDictionary<String, String>();
public override System.Threading.Tasks.Task OnConnected()
{
UsersOnline.TryAdd(Context.ConnectionId, Context.User.Identity.GetUserId());
return base.OnConnected();
}
一条警告:
除非在认证之后映射SignalR,否则 Context.User 将为空。
在客户端上将连接 ID 存储在变量中也可能会有益,这样您可以稍后将其传递给您的方法。
var connectionId;
var testHub = $.connection.testHub;
$.connection.hub.start().done(function () {
connectionId = $.connection.hub.id;
}
中心:
中心可用于与Web服务通信。在此示例中,我将将其用作SOAP服务,但REST应该也可以正常工作。
public void LongRunningTask(String ConnectionId)
{
using (var svc = new Services.MyWebService.SignalRTestServiceClient())
{
svc.LongRunningTask(ConnectionId);
}
}
请注意,我们也将连接ID传递给服务。当服务开始向MVC项目发送消息以传递给客户端时,这一点就发挥作用了。
监听器或Web API:
在MVC网站上设置一个监听器控制器或Web API,以接收来自Web服务的消息。
public ActionResult SignalR(String Message, String Type, String ConnectionId)
{
if (!String.IsNullOrWhiteSpace(Message) && !String.IsNullOrWhiteSpace(Type) && !String.IsNullOrWhiteSpace(ConnectionId))
{
if (Type == "ShowAlert")
{
bool UserIsOnline = Hubs.TestHub.UsersOnline.ContainsKey(ConnectionId);
IHubContext TestHub = GlobalHost.ConnectionManager.GetHubContext<Hubs.TestHub>();
if (UserIsOnline)
{
TestHub.Clients.Client(ConnectionId).showAlert(Message);
}
else
{
List<String> UserIdsInRole = new List<String>();
using (var connection = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString()))
{
UserIdsInRole = connection.Query<String>(@"
SELECT ur.UserId
FROM AspNetUserRoles ur
JOIN AspNetRoles r ON ur.RoleId = r.Id
WHERE r.Name = @rolename
", new { rolename = "SpecialRole" }).ToList();
}
List<String> ActiveUsersInRoleConnectionIds = Hubs.TestHub.UsersOnline.Where(x => UserIdsInRole.Contains(x.Value)).Select(y => y.Key).ToList();
TestHub.Clients.Clients(ActiveUsersInRoleConnectionIds).showAlert(Message);
}
}
}
return new HttpStatusCodeResult(200);
}
Web服务:
执行长时间运行任务的Web服务方法应该接受客户端ID,以便可以将其发送回侦听器控制器或Web API。它可以使用类似于以下方法(使用RestSharp)连接回MVC项目:
public void ShowAlert(String Message, String ConnectionId)
{
RestClient Client = new RestClient("http://localhost:8888");
RestRequest Request = new RestRequest("/Listener/SignalR", Method.POST);
Request.Parameters.Add(new Parameter() { Name = "Message", Type = ParameterType.QueryString, Value = Message });
Request.Parameters.Add(new Parameter() { Name = "Type", Type = ParameterType.QueryString, Value = "ShowAlert" });
Request.Parameters.Add(new Parameter() { Name = "ConnectionId", Type = ParameterType.QueryString, Value = ConnectionId });
IRestResponse Response = Client.Execute(Request);
}
演示:
我进行了一个概念验证,并将其上传到Github。
onConnected
和onDisconnected
方法来获取用户列表并相应地存储到内存/永久性数据库中。 - Prasad PhuleonConnected
和onDisconnected
方法移到 SignalR 服务中。现在找到“如何从 HTML(JS SignalR 代码)页面将 userid、connectionid 和 applicationId 发送到 SignalR 服务的 onConnected 方法”或其他解决方案? - Prasad Phule