SignalR 的 generated proxy
服务端
public class ContosoChatHub : Hub { public void NewContosoChatMessage(string name, string message) { Clients.All.addContosoChatMessageToPage(name, message); } }
JavaScript 客户端
generated proxy
var contosoChatHubProxy = $.connection.contosoChatHub; contosoChatHubProxy.client.addContosoChatMessageToPage = function (name, message) { console.log(name + ' ' + message); }; $.connection.hub.start().done(function () { // Wire up Send button to call NewContosoChatMessage on the server. $('#newContosoChatMessage').click(function () { contosoChatHubProxy.server.newContosoChatMessage($('#displayname').val(), $('#message').val()); $('#message').val('').focus(); }); });
非 generated proxy
var connection = $.hubConnection(); var contosoChatHubProxy = connection.createHubProxy('contosoChatHub'); contosoChatHubProxy.on('addContosoChatMessageToPage', function(name, message) { console.log(name + ' ' + message); }); connection.start().done(function() { // Wire up Send button to call NewContosoChatMessage on the server. $('#newContosoChatMessage').click(function () { contosoChatHubProxy.invoke('newContosoChatMessage', $('#displayname').val(), $('#message').val()); $('#message').val('').focus(); }); })
什么时候使用 generated proxy
如果你要给客户端的方法注册多个事件处理器,那么你就不能使用 generated proxy。如果你不使用 generated proxy ,那么你就不能引用 "signalr/hubs" URL。
客户端设置
首先需要引用jQuery,SignalR,signalr/hubs
<script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery.signalR-2.1.0.min.js"></script> <script src="signalr/hubs"></script>
如何引用动态的 generated proxy
ASP.NET MVC 4 or 5 Razor
<script src="~/signalr/hubs"></script>
ASP.NET MVC 3 Razor
<script src="@Url.Content("~/signalr/hubs")"></script>
ASP.NET Web Forms
<script src='<%: ResolveClientUrl("~/signalr/hubs") %>'></script>
/signalr/hubs 是 SignalR 自动生成的,当你启动调试的时候会在Script Documents 看到它
建立一个连接
建立一个连接 (generated proxy方式)
var contosoChatHubProxy = $.connection.contosoChatHub; contosoChatHubProxy.client.addContosoChatMessageToPage = function (name, message) { console.log(userName + ' ' + message); }; $.connection.hub.start() .done(function(){ console.log('Now connected, connection ID=' + $.connection.hub.id); }) .fail(function(){ console.log('Could not Connect!'); });
建立一个连接 (非 generated proxy方式)
var connection = $.hubConnection(); var contosoChatHubProxy = connection.createHubProxy('contosoChatHub'); contosoChatHubProxy.on('addContosoChatMessageToPage', function(userName, message) { console.log(userName + ' ' + message); }); connection.start() .done(function(){ console.log('Now connected, connection ID=' + connection.id); }) .fail(function(){ console.log('Could not connect'); });
$.connection.hub 和 $.hubConnection() 创建的对象是一样的。
start 方法的异步执行
start 方法是异步执行的,它返回一个 jQuery Deferred 对象,你可以给 pipe, done, and fail 添加回调函数。
当你直接把 "Now connected" 代码放在 start 方法后面,而不是放在 .done 的回调函数里,那么 console.log 会在连接前就执行。
怎么开启跨域连接
首先需要安装 Microsoft.Owin.Cors ,然后使用 Map 和 RunSignalR 代替 MapSignalR,跨域中间件只会在需要跨域的 SignalR 请求里执行。
using Microsoft.AspNet.SignalR; using Microsoft.Owin.Cors; using Owin; namespace MyWebApplication { public class Startup { public void Configuration(IAppBuilder app) { // Branch the pipeline here for requests that start with "/signalr" app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); }); } } }
如何处理连接的生命周期事件
SignalR 提供了下述你可以捕获的生命周期事件。
- starting: 在任何数据发送之前执行。
- received: 当任何数据通过连接获取到的时候执行。可以得到数据。
- connectionSlow: 当客户端检测到缓慢或者不流畅的连接的时候执行。
- reconnecting: 当潜在的协议重新开始连接的时候执行。
- reconnected: 当潜在的协议以及重新建立连接的时候执行。
- stateChanged: 当连接的状态发生改变的时候执行。可以提供一个旧的和新的状态(Connecting, Connected, Reconnecting, 或者 Disconnected)。
- disconnected: 当连接中断以后执行。
捕获 connectionSlow 事件 (generated proxy方式)
$.connection.hub.connectionSlow(function () { console.log('We are currently experiencing difficulties with the connection.') });
捕获 connectionSlow 事件 (非generated proxy方式)
var connection = $.hubConnection(); connection.connectionSlow(function () { console.log('We are currently experiencing difficulties with the connection.') });
如何捕获和处理异常
如果你不在服务端明确地打开详细错误信息,那么SignalR只会列出一些简单的错误信息,你可以通过下面的代码开启详细错误信息记录。
var hubConfiguration = new HubConfiguration(); hubConfiguration.EnableDetailedErrors = true; app.MapSignalR(hubConfiguration);
给错误事件添加一个捕获方法
generated proxy 方式
$.connection.hub.error(function (error) { console.log('SignalR error: ' + error) });
非 generated proxy 方式
var connection = $.hubConnection(); connection.error(function (error) { console.log('SignalR error: ' + error) });
方法调用的时候捕获异常
generated proxy 方式
contosoChatHubProxy.newContosoChatMessage(userName, message) .fail(function(error) { console.log( 'newContosoChatMessage error: ' + error) });
非 generated proxy 方式
contosoChatHubProxy.invoke('newContosoChatMessage', userName, message) .fail(function(error) { console.log( 'newContosoChatMessage error: ' + error) });
开启客户端日志记录
generated proxy 方式
$.connection.hub.logging = true;
$.connection.hub.start();
非 generated proxy 方式
var connection = $.hubConnection(); connection.logging = true; connection.start();
不使用生成代理JS的实现
可能有同学会觉得使用集线器很麻烦,要么引入虚拟目录,要么在生成期间生成js文件,再引入js文件进行开发。难道就没有比较清爽的方式吗?这个当然是有的,先不要(。・∀・)ノ゙嗨皮起来, 看完后再做出选择
简单看一下生成的js文件,其实代码一大堆,我们也可以根据这个js来写一个
首先我们需要有连接对象
let hubDemo = $.hubConnection("/simpleHub");
然后创建HubDemo类的代理
var proxy = hubDemo.createHubProxy("HubDemo");
然后就可以开启连接了,这里使用了代理对象执行 HelloService方法
hubDemo.start().done(function () { proxy.invoke("HelloService"); });
记得HelloService方法里会调用HelloClient函数,所以这个也是不能少的
proxy.on("helloClient", function() { console.log("收到服务器的问候"); })
这时候可以运行起来看看效果了,嗯 这看起来很完美
完整代码如下,可以看到这些类名和方法名都是需要去指定的,也就是虽然完全解耦但是这对开发带来了难度,而这些代理也只是对代理生成的js的简化版,而且也没有智能提醒了,因为要自己写-.- 两种方式各有利弊,用哪个都不错。根据项目情况自行选择吧
let hubDemo = $.hubConnection("/simpleHub"); var proxy = hubDemo.createHubProxy("HubDemo"); hubDemo.start().done(function () { proxy.invoke("HelloService"); }); proxy.on("helloClient", function() { console.log("收到服务器的问候"); });
HubName与HubMethodName
我们可以使用这两个特性为我们的方法与类进行重命名,比如方法名是Hello,但是我想要客户端调用的是MyHello。
[HubMethodName("Hello")] public void HelloService(string age1, int age2) { Clients.All.helloClient(); }
HubName作用与HubMethodName的作用是类似的,不同的是作用于类上
[HubName("HubDemo2")] public class HubDemo : Hub