目标:通过在数据库中存储新消息(发布到Web API)并将其推送到单个侦听客户端(SignalR)来促进2个用户之间的聊天。
以下是我的担忧:
我想过尝试:
也许我的应用程序太简单了,不需要更好的设计?
这是我到目前为止所拥有的:
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
答案 0 :(得分:4)
我认为您不需要使用任何复杂的设计模式,而您的需求就是这么简单。 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会提前/返回)。
3)您不需要手动处理JSON。只需按下对象,C#SignalR库就会为您处理编码和解码。
4)根据我的经验,SignalR在重新连接时可能有点不稳定,特别是对于IUserIdProvider(我见过客户端和服务器都认为它们已经重新连接但实际上没有推送的情况)。因此,我建议使用类似https://github.com/DamianEdwards/NDCLondon2013/tree/master/UserPresence的内容来为您提供更可靠(或至少更可调试)的用户状态管理。