标签:
最近接手的一个项目中,涉及到一个简单的消息模块,由于之前有简单了解过SignalR,所以打算尝试着摸索摸索~!
首先,通过Nuget管理器添加Microsoft ASP.NET SignalR引用~目前最新版本2.2.0,依赖项目也有点多,什么Microsoft.AspNet.SignalR.JS,Microsoft.AspNet.SignalR.SystemWeb,还有Owin相关的项目,没法咯,一起统一引用!
添加启动设置
1 [assembly: OwinStartup(typeof(SignalR.Demo.OwinStartup))] 2 3 namespace SignalR.Demo 4 { 5 public class OwinStartup 6 { 7 public void Configuration(IAppBuilder app) 8 { 9 app.MapSignalR(); 10 } 11 } 12 }
接下来,在原有的Web API项目中Controller里面添加一个支持SignalR的基类~
1 /// <summary> 2 /// SignalR ApiController 3 /// </summary> 4 /// <typeparam name="THub"></typeparam> 5 public abstract class ControllerWithHub<THub> : ApiBase 6 where THub : IHub 7 { 8 private readonly Lazy<IHubContext> _hub = new Lazy<IHubContext>( 9 () => GlobalHost.ConnectionManager.GetHubContext<THub>() 10 ); 11 12 protected IHubContext Hub 13 { 14 get { return _hub.Value; } 15 } 16 }
然后写了一个类似于Hello World的Hub。
1 [HubName("message")] 2 public class MessageHub : Hub 3 { 4 public void Hello() 5 { 6 Clients.Others.addMessage(string.Format("用户:{0},进入聊天室!", Context.ConnectionId)); 7 Clients.Caller.addMessage("Welcome!"); 8 } 9 10 public override Task OnConnected() 11 { 12 return base.OnConnected(); 13 } 14 15 public override Task OnDisconnected(bool stopCalled) 16 { 17 return base.OnDisconnected(stopCalled); 18 } 19 20 public override Task OnReconnected() 21 { 22 return base.OnReconnected(); 23 } 24 }
最后就是API接口啦~
1 public class MessageController : ControllerWithHub<MessageHub> 2 { 3 private static readonly List<string> MessageList = new List<string> 4 { 5 "Init Message", 6 "Second Message" 7 }; 8 9 [HttpGet] 10 [Route("~/message/list")] 11 public List<string> List() 12 { 13 lock (MessageList) 14 { 15 return MessageList; 16 } 17 } 18 19 [HttpPost] 20 [Route("~/message/send")] 21 public object Send([FromBody] string message) 22 { 23 var id = "id".Form(""); 24 var msg = "message".Form(string.Empty); 25 lock (MessageList) 26 { 27 MessageList.Add(message); 28 message = string.Format("id:{2}[{0}]:<br/>{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msg, 29 id); 30 Hub.Clients.AllExcept(id).addMessage(message); 31 Hub.Clients.Client(id) 32 .addMessage(string.Format("我[{0}]:<br/>{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msg)); 33 return new {status = "success"}; 34 } 35 } 36 }
测试接口就算是基本完成啦~
再来看下客户端的调用
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"/> 5 <title></title> 6 <link rel="stylesheet" href="../css/amazeui.min.css"/> 7 <style> 8 .msg-list { 9 min-height: 230px; 10 border: solid 1px #eee; 11 width: 1000px; 12 margin: 10px auto; 13 height: 300px; 14 overflow-y: scroll; 15 } 16 </style> 17 </head> 18 <body> 19 <div class="msg-list"> 20 </div> 21 <div class="am-panel" style="width: 1000px;margin: 10px auto;"> 22 <textarea class="am-text-primary" style="width: 500px"></textarea> 23 <button class="btn-message am-btn am-btn-primary">Say</button> 24 </div> 25 <script src="../js/jquery.min.js"></script> 26 <script src="../js/jquery.signalR-2.2.0.min.js"></script> 27 <script type="text/javascript" src="http://localhost/signalr/hubs"></script> 28 <script> 29 (function ($) { 30 var messageHub = $.connection.message; 31 $.connection.hub.logging = true; 32 messageHub.client.addMessage = function (msg) { 33 $(".msg-list").append(‘<div>‘ + msg + ‘</div>‘); 34 }; 35 $.connection.hub.start().done(function () { 36 messageHub.server.hello(); 37 $(".btn-message").click(function () { 38 var msg = $(".am-text-primary"); 39 $.ajax({ 40 url: "http://localhost/message/send", 41 data: {id: $.connection.hub.id, message: msg.val()}, 42 type: ‘Post‘, 43 success: function () { 44 msg.val(""); 45 } 46 }); 47 }); 48 }); 49 })(jQuery); 50 </script> 51 </body> 52 </html>
本以为可以很轻松的搞定这个Demo,但是~
第一回合:
SignalR完全没有加载~
路径问题,小Case啦~
在页面JS中手动指定SignalR服务地址
$.connection.hub.url = "http://localhost/signalr";
但是问题并没有想我想象那么简单的解决~
由于之前的接口,我已经很粗暴的加入了跨域支持,怎么还会存在跨域的问题呢~
配置如下:
1 <system.webServer> 2 <httpProtocol> 3 <customHeaders> 4 <add name="Access-Control-Allow-Origin" value="*" /> 5 <add name="Access-Control-Allow-Methods" value="GET,POST" /> 6 <add name="Access-Control-Allow-Headers" value="content-type" /> 7 </customHeaders> 8 </httpProtocol> 9 <handlers> 10 <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> 11 <remove name="OPTIONSVerbHandler" /> 12 <remove name="TRACEVerbHandler" /> 13 <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> 14 </handlers> 15 </system.webServer>
于是乎,查阅了下官方说明~发现SignalR有着自己的跨域组件Microsoft.Owin.Cors,那就加上吧~在Nuget上找到它,并添加到项目中,稍微修改下启动设置:
1 [assembly: OwinStartup(typeof(SignalR.Demo.OwinStartup))] 2 3 namespace SignalR.Demo 4 { 5 public class OwinStartup 6 { 7 public void Configuration(IAppBuilder app) 8 { 9 app.Map("/signalr", map => 10 { 11 map.UseCors(CorsOptions.AllowAll); 12 var hubConfiguration = new HubConfiguration 13 { 14 EnableJSONP = true 15 }; 16 map.RunSignalR(hubConfiguration); 17 }); 18 } 19 } 20 }
但是,问题同样存在~,这下就纠结了,这是什么个情况!在测试了各种方式之后,问题依旧!于是乎,改用Chrome来看下,一下就找到问题出在哪了。
PS:Chrome真不愧是程序员的最爱啊!来张Chrome里面的报错信息:
这下错误信息就很清晰了,api返回的Access-Control-Allow-Origin居然是"http://localhost:63342, *",很明显是SignalR的跨域组件和我之前粗暴的配置文件冲突了~
那么只有换一种方式了~
1.注释掉配置文件中system.service里面的跨域支持相关的配置;
2.添加Web API的跨域支持组件System.Web.Cors;
3.在WebApiConfig中开启跨域支持;
config.EnableCors();
4.在Controller中配置跨域属性。
[EnableCors("*","*","*")] public class MessageController : ControllerWithHub<MessageHub>
大功告成啦,再来测试下。
成功跨域!~
标签:
原文地址:http://www.cnblogs.com/shoy/p/4377627.html