之前的文章介绍过Asp.net SignalR,  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:

    public class FeedHub : Hub
    {
        public void 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; }是简单的消息模型, 标题与正文属性:

    [Serializable]
    public class PushMessageModel
    {
        public int Id { get; set; }
        public string MSG_TITLE { get; set; }
        public string MSG_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是一个封装过的对象. 

    public class MQHubsConfig
    {
        private static ILogger log = new Logger("MQHubsConfig");
 
        /// <summary>
        /// Registers the mq listen and hubs.
        /// </summary>
        public static void RegisterMQListenAndHubs()
        {
            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下加载:

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_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))]
namespace RealTimeApp
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }
    }
}

接下来是客户端App.js:

function App() {
    var init = 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, 与服务端对应

function Feed() {
    var chat = undefined;
 
    var init = 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) {
            var selector = "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 {
<link href="/Content/themes/default/window.css" rel="stylesheet" />
<link href="~/Content/themes/default/progressbar.css" rel="stylesheet" />
<link href="~/Content/themes/default/linkbutton.css" rel="stylesheet" />
<script src="~/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 () {
            var app = new App();
        });
 
    </script>
}
 
 
<div class="row-fluid">
 
    <div class="span8">
        <div class="widget">
            <div class="widget-header">
                <h2>Feed</h2>
            </div>
            <div class="widget-content">
                <ul class="span12 feed-list"></ul>
            </div>
        </div>
    </div>
</div>
 
<script class="chat-template" type="text/x-jquery-tmpl">
    <li>
        <p>{{>Message}}</p>
    </li>
</script>
 
<script class="feed-template" type="text/x-jquery-tmpl">
    <li data-id="{{>Id}}">
        <div class="row-fluid">
 
            <div class="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(new ScriptBundle("~/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]
        public IHttpActionResult SendMessage(PushMessageModel messagemodel)
        {
            return SendToServer(messagemodel);
 
        }
 
        /// <summary>
        /// Sends to server.
        /// </summary>
        /// <param name="messagemodel">The messagemodel.</param>
        /// <returns></returns>
        private IHttpActionResult SendToServer(PushMessageModel messagemodel)
        {
 
            if (ModelState.IsValid)
            {
                if (messageRepository.SendMessage(messagemodel))
                {
                    log.Debug("发送成功!");
                    return Ok();
                }
                else
                {
                    log.ErrorFormat("发送失败!{0}", messagemodel);
                    return Content(HttpStatusCode.ExpectationFailed, new Exception("send message error"));
                }
            }
            else
            {
                log.ErrorFormat("参数验证失败!{0}", messagemodel);
                return Content(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的关键代码:

    public class MessageRepository:IMessageRepository
    {
        private static ILogger log = new Logger("MessageRepository");
 
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="messagemodel"></param>
        /// <returns></returns>
        public bool SendMessage(PushMessageModel messagemodel)
        {
          var activemq = new ActiveMQAdapter<PushMessageModel>(MQConfig.MQIpAddress, MQConfig.QueueDestination);
          return activemq.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

Asp.net SignalR 实现服务端消息推送到Web端的更多相关文章

  1. SSE(Server-sent events)技术在web端消息推送和实时聊天中的使用

    最近在公司闲着没事研究了几天,终于搞定了SSE从理论到实际应用,中间还是有一些坑的. 1.SSE简介 SSE(Server-sent events)翻译过来为:服务器发送事件.是基于http协议,和W ...

  2. python 全栈开发,Day131(向app推送消息,玩具端消息推送)

    先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.4.zip 注意:由于涉及到 ...

  3. 使用SignalR实现服务端消息推送

    概述 这篇文章参考的是Server Broadcast with SignalR 2这篇教程,很不错的一篇教程,如果有兴趣的话可以查看原文,今天记录下来作为一个学习笔记,这样今后翻阅会更方便一点. 这 ...

  4. SignalR Self Host+MVC等多端消息推送服务(1)

    一.概述 由于项目需要,最近公司项目里有个模块功能,需要使用到即时获得审批通知:原本的设计方案是使用ajax对服务器进行定时轮询查询,刚刚开始数据量和使用量不大的时候还好,后来使用量的增加和系统中各种 ...

  5. SignalR Self Host+MVC等多端消息推送服务(2)

    一.概述 上次的文章中我们简单的实现了SignalR自托管的服务端,今天我们来实现控制台程序调用SignalR服务端来实现推送信息,由于之前我们是打算做审批消息推送,所以我们的demo方向是做指定人发 ...

  6. Spring mvc服务端消息推送(SSE技术)

    SSE技术是基于单工通信模式,只是单纯的客户端向服务端发送请求,服务端不会主动发送给客户端.服务端采取的策略是抓住这个请求不放,等数据更新的时候才返回给客户端,当客户端接收到消息后,再向服务端发送请求 ...

  7. SignalR 中丰富多彩的消息推送方式

    在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能:本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开 ...

  8. android通过服务实现消息推送

    这里运用到的andorid知识模块主要有Notification和Service,和一个android-async-http-master开源框架 android项目中,有时会有这样一种需求:客户每隔 ...

  9. ASP.NET 微信公众平台模板消息推送功能完整开发

    最近公众平台的用户提出了新需求,他们希望当收到新的邮件或者日程的时候,公众平台能主动推送一条提醒给用户.看了看平台提供的接口,似乎只有[模板消息]能尽量满足这一需求,但不得不说微信提供的实例太少,而且 ...

随机推荐

  1. Javascript单元测试之QUnit

    首先去Qunit官网下载. Qunit有一个js脚本文件和一个css我们在页面中引入它. <script src="qunit-2.0.1.js"></scrip ...

  2. 关于c#动态加载程序集的一些注意事项

    Assembly下有LoadFile,LoadFrom等方法可以加载程序集. LoadFile只加载你给定路径的那个dll,LoadFrom会自动加载依赖的dll. 如:A依赖B,LoadFile(& ...

  3. 云计算之路-阿里云上:借助IIS Log Parser Studio分析“黑色30秒”问题

    今天下午15:11-15:13间出现了类似“黑色30秒”的状况,我们用强大的IIS日志分析工具——Log Parser Studio进行了进一步的分析. 分析情况如下—— 先看一下Windows性能监 ...

  4. Deep learning:四十四(Pylearn2中的Quick-start例子)

    前言: 听说Pylearn2是个蛮适合搞深度学习的库,它建立在Theano之上,支持GPU(估计得以后工作才玩这个,现在木有这个硬件条件)运算,由DL大牛Bengio小组弄出来的,再加上Pylearn ...

  5. Network - DNS

    珠玉在前,不再赘言 DNS 原理入门 从理论到实践,全方位认识DNS(理论篇) 从理论到实践,全方位认识DNS(实践篇)

  6. 让你心动的 HTML5 & CSS3 效果【附源码下载】

    这里集合的这组 HTML5 & CSS3 效果,有的是网站开发中常用的.实用的功能,有的是先进的 Web 技术的应用演示.不管哪一种,这些案例中的技术都值得我们去探究和学习. 超炫的 HTML ...

  7. Android开发资源获取国内代理(转载)

    Android Dev Tools官网地址:www.androiddevtools.cn 收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Androi ...

  8. 为什么是梯度下降?SGD

    在机器学习算法中,为了优化损失函数loss function ,我们往往采用梯度下降算法来进行优化.举个例子: 线性SVM的得分函数和损失函数分别为:                         ...

  9. HTML5五种客户端离线存储方案

    最近折腾HTML5游戏需要离线存储功能,便把目前可用的几种HTML5存储方式研究了下,基于HT for Web写了个综合的实例,分别利用了Cookie.WebStorage.IndexedDB以及Fi ...

  10. 《ASP.NET SignalR系列》第四课 SignalR自托管(不用IIS)

    从现在开始相关文章请到: http://lko2o.com/moon 接着上一篇:<ASP.NET SignalR系列>第三课 SignalR的支持平台 一.概述 SignalR常常依托于 ...