我使用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()中得到解决,当它被实例化时在我的服务中被调用,所以它只会在它之后执行回调& #39;已成功连接)
它到达我的.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
文件中找到的代码在服务器上(我不是&#39因为我不使用生成的代理,所以需要这个,我只是将其包含在内,以便我可以检查它们的底层代码。
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)));
}
};
答案 0 :(得分:6)
好吧,终于明白了。我遇到了两个不同的问题。
第一个问题:
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
并且瞧,它有效。它现在成功地击中了我的断点。