Asp.netSignalR实现服务端消息推送到Web端

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

          之前的文章介绍过asp.netSignalR,  ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.  今天我们来实现服务端消息推送到Web端,   首先回顾一下它抽象层次图是这样的:

实际上 Asp.net SignalR 2 实现 服务端消息推送到Web端, 更加简单. 为了获取更好的可伸缩性, 我们引入消息队列, 看如下基本流程图:

消息队列MQ监听, 在Web site 服务端一收到消息,马上通过Signalr 推送广播到客户端.  创建ASP.NET MVC WEB APP,  从NuGet 安装SignalR 2.12

Install-Package Microsoft.AspNet.SignalR

具体实现代码,是这样的,我们增加一个空的Hub:

publicclassFeedHub : Hub

{

publicvoidInit()

{

}

}

 

.csharpcode, .csharpcodePRe

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }是简单的消息模型, 标题与正文属性:

[Serializable]

publicclassPushMessageModel

{

publicintId { get; set; }

publicstringMSG_TITLE { get; set; }

publicstringMSG_CONTENT { get; set; }

}

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }服务端推送具体类,记录日志, 创建消息队列实例,监听, 等待收取消息. 这里我们使用的是AcitveMQ的.net客户端. ActiveMQListenAdapter是一个封装过的对象. 

publicclassMQHubsConfig

{

privatestaticILogger log =newLogger("MQHubsConfig");

 

/// <summary>

/// Registers the mq listen and hubs.

/// </summary>

publicstaticvoidRegisterMQListenAndHubs()

{

var activemq = Megadotnet.MessageMQ.Adapter.ActiveMQListenAdapter<PushMessageModel>.Instance(MQConfig.MQipAddress, MQConfig.QueueDestination);

activemq.MQListener += m =>

{

log.InfoFormat("从MQ收到消息{0}", m.MSG_CONTENT);

GlobalHost.ConnectionManager.GetHubContext<FeedHub>().Clients.All.receive(m);

};

 

activemq.ReceviceListener<PushMessageModel>();

}

}

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }

上面有一句关键代码GlobalHost.ConnectionManager.GetHubContext<FeedHub>().Clients.All.receive(m);  这里使用了GetHubContext方法后,直接来广播消息.

需要在MVCapplication下加载:

publicclassMvcApplication : System.Web.HttpApplication

{

protectedvoidApplication_Start()

{

AreaRegistration.RegisterAllAreas();

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

RouteConfig.RegisterRoutes(RouteTable.Routes);

BundleConfig.RegisterBundles(BundleTable.Bundles);

MQHubsConfig.RegisterMQListenAndHubs();

}

}

同时需要增加一个Starup.cs, 用于Owin

[assembly: OwinStartup(typeof(RealTimeApp.Startup))]

namespaceRealTimeApp

{

publicclassStartup

{

publicvoidConfiguration(IAppBuilder app)

{

// Any connection or hub wire up and configuration should go here

app.MapSignalR();

}

}

}

接下来是客户端App.js:

functionApp() {

varinit =function() {

Feed();

$.connection.hub.logging =true;

$.connection.hub.start()

.done(function() {

console.log("Connected!");

$(document).trigger("Connected");

})

.fail(function() { console.log("Could not Connect!"); });

};

 

init();

};

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }Feed.js 具体与SignalR.js通信, 创建名为receive的function, 与服务端对应

functionFeed() {

varchat = undefined;

 

varinit =function() {

// Reference the auto-generated proxy for the hub.

chat = $.connection.feedHub;

// Create a function that the hub can call back to display messages.

chat.client.receive =function(item) {

varselector ="ul.feed-list li[data-id="+ item.Id +"]";

if(!($(selector).length > 0)) {

$("ul.feed-list").prepend($(".feed-template").render(item));

$("ul.feed-list li:gt(3)").remove();

}

 

$.messager.show({

title:'Tips',

msg: item.MSG_CONTENT,

showType:'show'

});

 

};

 

// Start the connection.

$.connection.hub.start().done(function() {

chat.server.init();

});

 

};

 

init();

};

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }        上面的javascript代码与服务端有通信, 具体看如下图:

       

        在Index.cshtml,  我们需要引用SignalR客户端JS, 放置hubs, 这里我们使用了jsrender,  easyui.js 来呈现推送的消息.

@model dynamic

 

@section Scripts {

<linkhref="/Content/themes/default/window.CSS"rel="stylesheet"/>

<linkhref="~/Content/themes/default/progressbar.css"rel="stylesheet"/>

<linkhref="~/Content/themes/default/linkbutton.css"rel="stylesheet"/>

<scriptsrc="~/Scripts/jquery.signalR-2.1.2.min.js"></script>

<!--Reference the autogenerated SignalR hub script. -->

<script src="~/signalr/hubs"></script>

 

<script src="~/Scripts/jsrender.js"></script>

<script src="~/Scripts/jquery.easyui.min-1.4.1.js"></script>

 

@Scripts.Render("~/Scripts/project.js")

 

<script type="text/Javascript">

$(document).ready(function() {

varapp =newApp();

});

 

</script>

}

 

 

<divclass="row-fluid">

 

<divclass="span8">

<divclass="widget">

<divclass="widget-header">

<h2>Feed</h2>

</div>

<divclass="widget-content">

<ulclass="span12 feed-list"></ul>

</div>

</div>

</div>

</div>

 

<scriptclass="chat-template"type="text/x-jquery-tmpl">

<li>

<p>{{>Message}}</p>

</li>

</script>

 

<scriptclass="feed-template"type="text/x-jquery-tmpl">

<li data-id="{{>Id}}">

<divclass="row-fluid">

 

<divclass="span8">

<h3>{{>MSG_CONTENT}}</h3>

</div>

</div>

</li>

</script>

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }上代码服务端引用js的Script.Render, 需要在BundleConfig.cs中加入以下代码:

bundles.Add(newScriptBundle("~/Scripts/project.js")

.IncludeDirectory("~/Scripts/Project","*.js",false));

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }同时我们构建一个WebAPI来发送需要推送的消息, 片断代码:

/// <summary>

/// SendMessage

/// </summary>

/// <param name="messagemodel">The messagemodel.</param>

/// <returns></returns>

[HttpPost]

publicIHttpActionResult SendMessage(PushMessageModel messagemodel)

{

returnSendToServer(messagemodel);

 

}

 

/// <summary>

/// Sends to server.

/// </summary>

/// <param name="messagemodel">The messagemodel.</param>

/// <returns></returns>

privateIHttpActionResult SendToServer(PushMessageModel messagemodel)

{

 

if(ModelState.IsValid)

{

if(messageRepository.SendMessage(messagemodel))

{

log.Debug("发送成功!");

returnOk();

}

else

{

log.ErrorFormat("发送失败!{0}", messagemodel);

returnContent(HttpStatusCode.ExpectationFailed,newException("send message error"));

}

}

else

{

log.ErrorFormat("参数验证失败!{0}", messagemodel);

returnContent(HttpStatusCode.BadRequest, ModelState);

}

 

}

 

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; }发送消息到ActiveMQ的关键代码:

publicclassMessageRepository:IMessageRepository

{

privatestaticILogger log =newLogger("MessageRepository");

 

/// <summary>

/// 发送消息

/// </summary>

/// <param name="messagemodel"></param>

/// <returns></returns>

publicboolSendMessage(PushMessageModel messagemodel)

{

var activemq =newActiveMQAdapter<PushMessageModel>(MQConfig.MQIpAddress, MQConfig.QueueDestination);

returnactivemq.SendMessage<PushMessageModel>(messagemodel)>0;

}

}

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

{

background-color: #f4f4f4;

width: 100%;

margin: 0em;

}

.csharpcode .lnum { color: #606060; } 

如果您需要运行DEMO程序,需要构建基于ActiveMQ的消息队列,   运行效果是这样的, 我们在一个静态html中, 发送一个Ajax到webapi服务端,  发送后

另一个website网站收到后, 列表更新, 并在右下角弹出框

IE的控制台输出:

HTML1300: Navigation occurred.

File: Index

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Client subscribed to hub 'feedhub'.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Negotiating with '/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22feedhub%22%7D%5D'.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: This browser doesn't support SSE.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Binding to iframe's load event.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Iframe transport started.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: foreverFrame transport selected. Initiating start request.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: The start request succeeded. Transitioning to the connected state.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Now monitoring keep alive with a warning timeout of 13333.333333333332 and a connection lost timeout of 20000.

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Invoking feedhub.Init

Connected!

[11:05:25 GMT+0800 (China Standard Time)] SignalR: Invoked feedhub.Init

[11:07:12 GMT+0800 (China Standard Time)] SignalR: Triggering client hub event 'receive' on hub 'FeedHub'.

[11:07:18 GMT+0800 (China Standard Time)] SignalR: Triggering client hub event 'receive' on hub 'FeedHub'.

[11:07:32 GMT+0800 (China Standard Time)] SignalR: Triggering client hub event 'receive' on hub 'FeedHub'.

[11:07:51 GMT+0800 (China Standard Time)] SignalR: Triggering client hub event 'receive' on hub 'FeedHub'.

[11:09:25 GMT+0800 (China Standard Time)] SignalR: Triggering client hub event 'receive' on hub 'FeedHub'.

上面粗体是 最后我们发的第5条信息控制台的输出.

 

好了,到这儿, 由于篇幅有限, 示例代码没有全部展示, 可以在这儿下载,  需要安装ActiveMQ

 

希望对您开发实时Web App有帮助.

你可能感兴趣的文章:

SignalR介绍与Asp.net

如有想了解更多软件,系统 IT,企业信息化 资讯,请关注我的微信订阅号:

作者:Petter Liu

出处:http://www.cnblogs.com/wintersun/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

该文章也同时发布在我的独立博客中-Petter Liu Blog。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航