【问题标题】:SignalR not invoking method on serverSignalR 不在服务器上调用方法
【发布时间】:2015-05-06 04:23:25
【问题描述】:

我正在使用 AngularJS 创建一个 SignalR 服务,该服务连接到我指定的集线器并公开 .on.invoke 方法,以便我的控制器可以侦听来自服务器的事件并调用服务器上的方法。

这是我服务的相关部分:

        return {
            on: function (eventName, callback) {
                hub.on(eventName, function (result) {
                    $root.$apply(function () {
                        if (callback) {
                            callback(result);
                        }
                    });
                });
            },
            ready: function (callback) {
                return isLoaded.then(function () {
                    callback();
                });
            },
            invoke: function (methodName, args, callback) {
                return hub.invoke.apply(hub, $.merge([methodName], $.makeArray(args))).done(function (result) {
                    $root.$apply(function () {
                        if (callback) {
                            callback(result);
                        }
                    });
                });
            },
            connection: connection
        };

我的集线器连接完美,但是当我尝试调用我的调用时,没有任何反应。这就是我所说的:

    var chatHub = hub('chatHub');

    chatHub.on('userConnected', function (user) {
        console.log(user);
    });

    chatHub.ready(function () {
        chatHub.invoke('Connect', [ // also tried 'connect' here
            { Name: $root.auth.profile.name, Picture: $root.auth.profile.picture },
            { RoomKey: $routeParams.roomKey, RoomID: $routeParams.roomId }
        ]);
    });

因此,如果您查看从我的服务返回的.ready() 函数,它使用了一个承诺,即当它被解析时将执行我传递给它的回调。效果很好(promise isLoaded 在我的 connection.start().done() 中解决,它在实例化时在我的服务内部调用,因此它只会在成功连接后执行回调)

它访问了我的 .invoke 方法(我已通过 console.log 确认了这一点),但从未在集线器上调用该方法,如下所示:

public class ChatHub : Hub {
    public async void Connect(User user, Room room) {
        // ommitted
    }
}

我传递给它的对象有这样的结构:

public class Room {
    public int RoomKey { get; set; }
    public string RoomID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public List<User> Users { get; set; }
    public List<Message> Messages { get; set; }
}

public class User {
    public string Name { get; set; }
    public string Picture { get; set; }
}

所以我认为我的论点没有问题,因为它们不需要任何东西,所以它不会抱怨我只传递了几个论点(我唯一需要的论点)。

为了清楚起见,在我的chatHub.invoke('Connect', ...) 中,我使用的是基于我在~/signalr/hubs 文件中找到的这段代码在服务器上的情况(我不需要这个,因为我不使用生成的代理,我只是暂时包含了它,所以我可以检查他们的底层代码)

    proxies['chatHub'] = this.createHubProxy('chatHub'); 
    proxies['chatHub'].client = { };
    proxies['chatHub'].server = {
        connect: function (user, room) {
            return proxies['chatHub'].invoke.apply(proxies['chatHub'], $.merge(["Connect"], $.makeArray(arguments)));
        }
    };

【问题讨论】:

  • 您应该调用 chatHub.invoke('connect',...) 吗?
  • 天哪。我想你是正确的。我曾一度将它命名为 UserConnect,但在调试和修复另一个问题时我做了很多 ctrl z。回到电脑前我会进行测试。
  • 我一直这样做 - 还要记住它会转换为 javascript 命名约定,因此当集线器方法是 UserConnect 时,调用应该使用 'userConnect'。
  • 当您使用.invoke().apply() 方法并在$.merge() 中传递它时,我的印象是您应该使用它在服务器上的情况。我一直使用生成的代理并按照您提到的那样完成骆驼案例,所以我可能是错的。
  • 我也一直使用生成的代理,所以我不确定那个,但我认为它遵循相同的约定......让我知道你回来测试时发现了什么它。

标签: c# angularjs signalr


【解决方案1】:

好吧,终于明白了。我遇到了两个不同的问题。

问题一:

chatHub.ready(function () {
    chatHub.invoke('Connect', [ // also tried 'connect' here
        { Name: $root.auth.profile.name, Picture: $root.auth.profile.picture },
        { RoomKey: $routeParams.roomKey, RoomID: $routeParams.roomId }
    ]);
});

这段代码将一个数据数组传递给.invoke(),然后:

        return hub.invoke.apply(hub, $.merge([methodName], $.makeArray(args)))

正在制作该数组的数组。因此,只需将其更改为:

        return hub.invoke.apply(hub, $.merge([methodName], args))

而且它是固定的。

然后我想,我可能应该在其中添加一些错误日志记录,看看它是否真的出错了,我只是没有对它做任何事情(没有.fail(),因此从来没有看到它)所以我把它改成了:

        return hub.invoke.apply(hub, $.merge([methodName], args))
            .done(function (result) {
                $root.$apply(function () {
                    if (callback) {
                        callback(result);
                    }
                });
            })
            .fail(function (error) {
                $log.error('Error invoking ' + methodName + ' on server: ' + error);
            });

这给了我这个惊人的错误信息和第二个问题

Error invoking connect on server: Error: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.

这是有道理的,因为我在服务器上的方法是 async void,我把它换成了 async Task,瞧,它奏效了。它现在成功地达到了我的断点。

【讨论】:

  • 很好的解释,节省了我的时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-24
相关资源
最近更新 更多