将REST Web API应用程序与SignalR集成?

时间:2015-08-11 20:42:18

标签: c# asp.net-web-api websocket signalr asp.net-web-api2

目标:通过在数据库中存储新消息(发布到Web API)并将其推送到单个侦听客户端(SignalR)来促进2个用户之间的聊天。

以下是我的担忧:

  • 除了Command and Query Responsibility Segregation (CQRS) PatternEvent Sourcing Pattern之外,我无法找到解决此问题的任何设计模式。这两个似乎都集中在复杂的实时应用程序上。我的应用程序有很多传统的REST功能,但目前唯一的实时组件是聊天,因此使用其中一种模式似乎没什么必要。
  • 是否有更简单的方法将基于REST的网站(Web API)与实时组件(SignalR)集成?
  • 我现在所做的事情就像是在混合两件完全不同的东西。

我想过尝试:

  • 使用events将我的POST处理程序耦合到我的推送处理程序 - 虽然我不确定这对我有帮助,因为我不希望发送消息"我的应用程序的一部分是从"接收"部分。
  • 将我的所有推送逻辑移动到由消息代理处理的作业中 - 这似乎不是必要的,但会创建更好的分离。根据这个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

1 个答案:

答案 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的内容来为您提供更可靠(或至少更可调试)的用户状态管理。