从WebAPI控制器调用SignalR hub存在问题

11

我不知道如何从WebAPI ApiController中调用SignalR hub。我已经创建了一个示例,您可以在这里下载此示例,它简化了问题并演示了该问题。

  1. 我从ASP.NET MVC WebAPI模板创建了一个新项目。
  2. 我向项目添加了一个名为ChatHub的新SignalR Hub。
  3. 添加了一个HTML页面,在加载时连接到ChatHub,加入一个组并向该组发送消息。 这非常有效。
  4. HTML页面还有一个按钮,当单击时会触发对ValuesController的post方法的ajax调用。 在ValuesController的post方法中,我想向该组的所有连接客户机广播消息。 我无法使其工作。

我有一个简单的SignalR hub,其中只有两个方法。

[HubName("chat")]
public class ChatHub : Hub
{
    public void Join(string room)
    {
        // NOTE: this is not persisted - ....
        Groups.Add(Context.ConnectionId, room);
    }

    public void Send(string room, string message)
    {
        var msg = String.Format(
            "{0}: {1}", Context.ConnectionId, message);
        Clients.Group(room).newMessage(msg);
    }
}

我创建了一个非常简单的 HTML 页面,在 DOM 准备就绪时连接到 Chat 中心,如下所示。

<html>
<head>
    <title>Simple Chat</title>
    <script src="Scripts/jquery-1.8.2.js" type="text/javascript"></script>
    <script src="Scripts/jquery.signalR-1.0.0.js"></script>
    <script src="signalr/hubs"></script>
    <script type="text/javascript">
        var chat;

        //$(function () {
        //    connectToHubs();
        //});
        $(connectToHubs);
        function connectToHubs() {
            $.connection.hub.logging = true;

            chat = $.connection.chat;
            chat.client.newMessage = onNewMessage;

            $.connection.hub.start({ transport: 'longPolling' }).done(function () {
                chat.server.join("TestGroup").done(function () {
                    chat.server.send("TestGroup", "message from html");
                });
            });

            $('#controller').click(postProficiencyUserAction);



        }
        var postProficiencyUserAction = function () {
            //var token = $('[name=__RequestVerificationToken]').val();
            var headers = {};
            //headers["__RequestVerificationToken"] = token;
            //var userAction = { createdOn: "2013-05-21T00:00:00", userId: "12345678-1234-1234-1234-000000000001", actionId: "12345678-1234-1234-1234-000000000003" };
            $.ajax({
                type: 'POST',
                url: 'http://localhost:58755/api/values',
                cache: false,
                headers: headers,
                contentType: 'application/json; charset=utf-8',
                data: 'test',
                dataType: "json",
                success: function () {

                },
                error: function () {

                }
            });
        };
        function onNewMessage(message) {
            // ... todo: validation !!!! :)
            $('#messages').append('<li>' + message + '</li>');
        };

    </script>
</head>
<body>
    <div>
        <h2>Chat</h2>
        <input type="button" id="controller" value="Controller Method" />
        <div>
            <h2>Message(s) Received</h2>
            <ul id="messages"></ul>
        </div>
    </div>
</body>
</html>

没有花哨的东西。当连接的中心接收到新消息时,将向无序列表添加一个新项。有一个按钮可以对ValuesController post方法进行Ajax调用。

public class ValuesController : ApiController
{
    // POST api/values
    public void Post([FromBody]string value)
    {
        var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
        hubContext.Clients.Group("TestGroup").send("TestGroup", "Called from Controller");
    }

Hub调用不起作用,没有报错,但是消息也没有收到。在Hub的“Send”方法中设置断点也不起作用。我感觉我做得没错。有人可以帮忙吗?同样,源代码可以在这里找到。

2个回答

16
你正在客户端上调用不同的方法:
API控制器
hubContext.Clients.Group("TestGroup").send("TestGroup", "Called from Controller");

中心

Clients.Group(room).newMessage(msg);

您想调用的方法是newMessage而不是send

chat.client.newMessage = onNewMessage;

David,非常感谢。看起来在服务器上,我可以调用hubContext.Clients.Group("TestGroup")的任何方法,例如hubContext.Clients.Group("TestGroup").helloNasty,客户端将自动能够响应相同的虚构方法。太神奇了。我需要学习一下C#的动态能力 :-) - DapperDanh
@dfowler:有没有办法从ApiController调用实际的ChatHub.Send方法?上述方法似乎绕过了ChatHub,直接到达Hub Context来执行ChatHub.Send的等效操作 - 但是我在ChatHub.Send中的其他任何内容都不会运行\需要在ApiController中复制?也许我只是漏掉了什么。 - mutex
1
不行。你不能从服务器调用中心方法。你需要将逻辑移到一个共享类中,这个类可以从中心内部和外部调用。 - davidfowl

2

对于ASP.NET Core,您现在可以执行以下操作:

[Route("some-route")]
public class MyController : ControllerBase
{
    private readonly IHubContext<MyHub> _hubContext;

    public MyController(IHubContext<MyHub> hubContext)
    {
        _hubContext = hubContext;
    }

    [HttpPost("message")]
    public async Task<ActionResult> SendMessage(string message)
    {
        await _hubContext.Clients.All.SendAsync("Message", message);
        return Ok();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接