方法返回值
Hub 的方法支持异步,方法声明为async Task<T>就可以了。如果Hub 中调用了异步的方法,那么一定要写成async。不能用TestAsync().Result 这种写法,否则Hub 方法只能调用一次就卡住了,后续调用就没反应了,不要使用WebClient 的异步,都换用HttpClient
Hub服务端
using Microsoft.AspNet.SignalR;
namespace SignalRApp
{
public class MyResult
{
public int code { get; set; }
public string msg { get; set; }
}
public class MyHub : Hub
{
public MyResult SendMsg()
{
var userName = Context.QueryString["userName"];
var password = Context.QueryString["password"];
MyResult r = null;
if (userName == "admin" && password == "123456")
{
//在服务端端中,我们自定义个onSendMessage事件,这个事件就是向客户端发送一个“大家好”
Clients.All.onSendMessage("大家好");
r = new MyResult() { code = 200, msg = "调用成功" };
}
else
{
r = new MyResult() { code = 400, msg = "调用失败" };
}
return r;
}
}
}
浏览器客户端
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.1.2.js"></script>
<script src="/signalr/hubs" type="text/javascript"></script>
</head>
<body>
<div>
<input type="button" value="调用方法" id="sendMsg"/>
</div>
<script type="text/javascript">
$(function () {
//这里是监听hub服务端给我(客户端)发动的消息(即:服务端调用onSendMessage方法,或者说服务端触发onSendMessage事件)
//当然我们也可以不监听。也可以监听。(如果不想监听这段代码可以不要)
$.connection.myHub.client.onSendMessage = function (msg) {
alert("消息来了:"+msg)
}
$.connection.hub.qs = { userName: "admin", password: "123456" };
$.connection.hub.start().done(function () {
alert("连接MyHub成功");
}).fail(function () { alert("连接MyHub失败") });
$("#sendMsg").click(function () {
//这里是调用服务端的sendMsg方法
$.connection.myHub.server.sendMsg().done(function (data) {
//在done中可以拿到服务端的方法返回值
//这个返回值一般是用来判断这次调用的成功或者是失败,及如果失败的话,失败的原因是什么
//例如你是否有权限调用这个方法,如果没有权限,服务端则会返回一个对应的调用失败代码
//即:这个成功或者是失败是指业务层面的成功或者失败,并不是程序常出现错误
alert(data.code + data.msg);
})
})
})
</script>
</body>
</html>
异常捕获
Hub 的方法中如果发生异常, 可以在fail() 回调方法中得知:hub.test().done(function(){alert(“成功”);}).fail(function(){alert(“错误);});
虽然SignalR 是在ASP.Net 项目中运行的,但是Hub 中的未处理异常是不会被MVC 的,ExceptionFilter 截获的。在服务器端可以通过自定义HubPipelineModule 来在服务器端捕获未处理异常,然后记录到日志等:
1>首先编写类继承自HubPipelineModule
public class ExceptionHubPipelineModule : HubPipelineModule
{
protected override void OnIncomingError(ExceptionContext exceptionContext,
IHubIncomingInvokerContext invokerContext)
{
//exceptionContext.Error; 就是异常对象可以记录到日志中
}
}
2>在Global 的Application_Start() 中编写GlobalHost.HubPipeline.AddModule(new ExceptionHubPipelineModule ());
namespace SignalRApp
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
//编写以下代码:
GlobalHost.HubPipeline.AddModule(new ExceptionHubPipelineModule());
}
}
}
3>像上面讲的,未处理异常可以在客户端每个方法的fail 中得知,如果想统一在客户端得知异常,那么可以在浏览器端写一个function,然后在服务器端调用这个function。比如浏览器端start 之前写一个
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.1.2.js"></script>
<script src="/signalr/hubs" type="text/javascript"></script>
</head>
<body>
<div>
<input type="button" value="调用方法" id="sendMsg"/>
</div>
<script type="text/javascript">
$(function () {
//这里是监听hub服务端给我(客户端)发动的消息(即:服务端调用onSendMessage方法,或者说服务端触发onSendMessage事件)
//当然我们也可以不监听。也可以监听。(如果不想监听这段代码可以不要)
//$.connection.myHub.client.onSendMessage = function (msg) {
// alert("消息来了:"+msg)
//}
//$.connection.hub.qs = { userName: "admin", password: "123456" };
//获取从服务端发送过来的未处理异常信息
$.connection.myHub.client.onGlobalServerError = function (errMsg) {
alert("这里可以得到我们在服务端自定义ExceptionHubPipelineModule类中捕获的未处理异常" + errMsg);
}
$.connection.hub.start().done(function () {
alert("连接MyHub成功");
}).fail(function () { alert("连接MyHub失败") });
//$("#sendMsg").click(function () {
// //这里是调用服务端的sendMsg方法
// $.connection.myHub.server.sendMsg().done(function (data) {
// //在done中可以拿到服务端的方法返回值
// //这个返回值一般是用来判断这次调用的成功或者是失败,及如果失败的话,失败的原因是什么
// //例如你是否有权限调用这个方法,如果没有权限,服务端则会返回一个对应的调用失败代码
// //即:这个成功或者是失败是指业务层面的成功或者失败,并不是程序常出现错误
// alert(data.code + data.msg);
// })
//})
})
</script>
</body>
</html>
然后ExceptionHubPipelineModule 中写
namespace SignalRApp
{
public class ExceptionHubPipelineModule: HubPipelineModule
{
/// <summary>
/// 捕获Hub的客户端
/// </summary>
/// <param name="exceptionContext">exceptionContext里面有异常消息</param>
/// <param name="invokerContext"></param>
protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext)
{
//base.OnIncomingError(exceptionContext, invokerContext);
//todo:将错误记录到Log4Net,或者分布式日记服务器
//所有连接的客户端
dynamic caller = invokerContext.Hub.Clients.Caller;
//自定义一个onGlobalServerError方法,将异常信息发送到客户端(一般情况下不需要把异常消息告诉客户端,只要告诉客户端出错消息编号就好了,这里仅仅是演示)
caller.onGlobalServerError(exceptionContext.Error.Message);
}
}
}