将 REST Web API 应用程序与 SignalR 集成?
Integrating REST Web API App with SignalR?
Objective:通过在数据库中存储新消息(发布到 Web API)并将其推送到单个监听客户端(SignalR)来促进 2 个用户之间的聊天。
以下是我的担忧:
- 除了 Command and Query Responsibility Segregation (CQRS) Pattern and Event Sourcing Pattern,我找不到任何解决此问题的设计模式。这两个似乎都专注于复杂的实时应用程序。我的应用程序有很多传统的 REST 功能,但目前唯一的实时组件是聊天,因此似乎没有必要使用其中一种模式。
- 是否有更简单的方法将基于 REST 的网站 (Web API) 与实时组件 (SignalR) 集成?
- 我现在所做的感觉就像是在混合两种完全不同的东西。
我想试试:
- 使用 events 将我的 POST 处理程序耦合到我的推送处理程序 - 虽然我不确定这对我有帮助,因为我不希望我的应用程序的 "send message" 部分从 "receive" 部分进化出一部分。
- 将我所有的推送逻辑移动到由消息代理处理的作业中——这似乎也没有必要,但会产生更好的分离。根据此 answer 我的理解是 SignalR 使用内存中的消息代理,这样广播就不会等待接收消息,因此不需要外部消息代理,除非我真的需要扩展。
也许我的应用程序太简单了,不需要更好的设计?
这是我目前的情况:
public class chatPush
{
public chatPush(){}
public push(string msg)
{
try{
string jsonMsg = JsonConvert.SerializeObject(msg);
await Clients.User(userId).send(jsonMsg);
}
catch
{
string errorMsg = //error with msg
await Clients.User(userId).send(errorMsg);
}
}
}
async Task<IHttpActionResult> PostMessage(Message msg)
db.Messages.Add(msg);
try
{
await db.SaveChangesAsync();
}
catch
{
//return error in JSON
}
//if update succeeded push it out
_chatPush.push(jsonMsg);
return //Success or Error code
我认为您不需要使用任何复杂的设计模式,而您的需求就这么简单。 SignalR 仅在 POST/etc 中运行良好。 API 和 MVC 的处理程序。
如果您需要扩展到多个前端服务器,则更复杂的设计会有所帮助,因为每个用户只会连接到您的一个 SignalR 主机,因此您需要担心持续的用户连接通过背板或数据库映射。但是 SignalR 在您需要时提供了不错的文档。
在基本设计方面我有几点建议:
1) 如果您在服务器端有 MessageHub,请创建一个 MessageHubHelper 以轻松将数据推送给正确的用户。
[Authorize]
public class MessageHub : Hub
{
}
public static class MessageHubHelper
{
private static readonly IHubContext _hubContext =
GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
public static IHubContext Context
{
get { return _hubContext; }
}
public static void Send(User user, Message message)
{
_hubContext.Clients.User(GetUserId(user)).Send(message);
}
public static void DoSomethingElse(User user, Message message)
{
_hubContext.Clients.User(GetUserId(user)).DoSomethingElse(message);
}
private static string GetUserId(User user)
{
return user.IdentityUser.UserName;
}
}
2) 确保仅在数据库提交成功时才推送数据(例如,在 try {} 中的 SaveChangesAsync 之后,除非 catch 会 throw/return 提早)。
3) 您不需要手动处理 JSON。只需按下对象,C# SignalR 库就会为您处理编码和解码。
4) 根据我的经验,SignalR 的重新连接可能有点不稳定,尤其是对于 IUserIdProvider(我见过客户端和服务器都认为它们已重新连接但实际上没有推送通过的情况)。因此,我推荐 https://github.com/DamianEdwards/NDCLondon2013/tree/master/UserPresence 之类的东西来为您提供更可靠(或至少更可调试)的用户状态管理。
Objective:通过在数据库中存储新消息(发布到 Web API)并将其推送到单个监听客户端(SignalR)来促进 2 个用户之间的聊天。
以下是我的担忧:
- 除了 Command and Query Responsibility Segregation (CQRS) Pattern and Event Sourcing Pattern,我找不到任何解决此问题的设计模式。这两个似乎都专注于复杂的实时应用程序。我的应用程序有很多传统的 REST 功能,但目前唯一的实时组件是聊天,因此似乎没有必要使用其中一种模式。
- 是否有更简单的方法将基于 REST 的网站 (Web API) 与实时组件 (SignalR) 集成?
- 我现在所做的感觉就像是在混合两种完全不同的东西。
我想试试:
- 使用 events 将我的 POST 处理程序耦合到我的推送处理程序 - 虽然我不确定这对我有帮助,因为我不希望我的应用程序的 "send message" 部分从 "receive" 部分进化出一部分。
- 将我所有的推送逻辑移动到由消息代理处理的作业中——这似乎也没有必要,但会产生更好的分离。根据此 answer 我的理解是 SignalR 使用内存中的消息代理,这样广播就不会等待接收消息,因此不需要外部消息代理,除非我真的需要扩展。
也许我的应用程序太简单了,不需要更好的设计?
这是我目前的情况:
public class chatPush
{
public chatPush(){}
public push(string msg)
{
try{
string jsonMsg = JsonConvert.SerializeObject(msg);
await Clients.User(userId).send(jsonMsg);
}
catch
{
string errorMsg = //error with msg
await Clients.User(userId).send(errorMsg);
}
}
}
async Task<IHttpActionResult> PostMessage(Message msg)
db.Messages.Add(msg);
try
{
await db.SaveChangesAsync();
}
catch
{
//return error in JSON
}
//if update succeeded push it out
_chatPush.push(jsonMsg);
return //Success or Error code
我认为您不需要使用任何复杂的设计模式,而您的需求就这么简单。 SignalR 仅在 POST/etc 中运行良好。 API 和 MVC 的处理程序。
如果您需要扩展到多个前端服务器,则更复杂的设计会有所帮助,因为每个用户只会连接到您的一个 SignalR 主机,因此您需要担心持续的用户连接通过背板或数据库映射。但是 SignalR 在您需要时提供了不错的文档。
在基本设计方面我有几点建议:
1) 如果您在服务器端有 MessageHub,请创建一个 MessageHubHelper 以轻松将数据推送给正确的用户。
[Authorize]
public class MessageHub : Hub
{
}
public static class MessageHubHelper
{
private static readonly IHubContext _hubContext =
GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
public static IHubContext Context
{
get { return _hubContext; }
}
public static void Send(User user, Message message)
{
_hubContext.Clients.User(GetUserId(user)).Send(message);
}
public static void DoSomethingElse(User user, Message message)
{
_hubContext.Clients.User(GetUserId(user)).DoSomethingElse(message);
}
private static string GetUserId(User user)
{
return user.IdentityUser.UserName;
}
}
2) 确保仅在数据库提交成功时才推送数据(例如,在 try {} 中的 SaveChangesAsync 之后,除非 catch 会 throw/return 提早)。
3) 您不需要手动处理 JSON。只需按下对象,C# SignalR 库就会为您处理编码和解码。
4) 根据我的经验,SignalR 的重新连接可能有点不稳定,尤其是对于 IUserIdProvider(我见过客户端和服务器都认为它们已重新连接但实际上没有推送通过的情况)。因此,我推荐 https://github.com/DamianEdwards/NDCLondon2013/tree/master/UserPresence 之类的东西来为您提供更可靠(或至少更可调试)的用户状态管理。