[转载]ASP.NET WebForm(MVC)下实现消息推送(提供简单Demo下载) - Good_Luck - 博客园

[转载]ASP.NET WebForm(MVC)下实现消息推送(提供简单Demo下载) – Good_Luck – 博客园.

由于项目需要,笔者最近需要实现Web客户端之间的消息的即时推送功能。

功能描述如下:

假设A,B,C用户登陆,内存记录下已登录的用户的信息,这时A在所在的客户端(SendInfo.aspx)页面向B发消息,则在B所在客户端页面(SendInfo.aspx)将弹出消息框。

关键点有两个:

1.保证客户端和服务端的连接

2.保证服务端能够向客户端广播消息

笔者是第一次做这样的实现,所以Google了一些资料,了解到可使用Comet,ajax轮询,WebSocket等技术实现,由于时间关系,发现有些技术不是很容易理解,这里做了一个简单Demo.希望能够达到抛砖引玉的作用,与大家分享,共同提高。

笔者做了两个框架下的实现,ASP.NET Web Form和ASP.NET MVC 下的尝试。

ASP.NET Web Form版:

项目组织结构

AsyncHandler.cs

View Code

复制代码
using System; using System.Collections.Generic; using System.Web; using System.Threading; namespace CometSample { public class WebIMAsyncHandler : IHttpAsyncHandler { #region IHttpAsyncHandler 成员

        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { string _UID = context.Request.Params["uid"]; WebIMClientAsyncResult _AsyncResult = new WebIMClientAsyncResult(context, cb, extraData); string _Content = context.Request.Params["content"]; string _Action = context.Request.Params["action"]; if (_Action == "login") { _UID = context.Request.Params["uid"]; _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Login(_UID, _AsyncResult); } else if (_Action == "logout") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Logout(_UID, _AsyncResult); } else if (_Action == "connect") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Connect(_AsyncResult); } else if (_Action == "getuserlist") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().GetUserList(_AsyncResult); } //增加消息发送
            else if (_Action == "sendmsg") { _AsyncResult.LoginID = _UID; //WebIMMessageHandler.Instance().GetUserList(_AsyncResult); //调用
 WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult); } //调用 //WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult);
            return _AsyncResult; } public void EndProcessRequest(IAsyncResult result) { } #endregion

        #region IHttpHandler 成员

        public bool IsReusable { get { return false; ; } } public void ProcessRequest(HttpContext context) { throw new NotImplementedException(); } #endregion } public class WebIMClientAsyncResult : IAsyncResult { bool m_IsCompleted = false; private HttpContext m_Context; private AsyncCallback m_Callback; private object m_ExtraData; private string m_Content; private string m_LoginID = string.Empty; public WebIMClientAsyncResult(HttpContext p_Context, AsyncCallback p_Callback, object p_ExtraData) { this.m_Context = p_Context; this.m_Callback = p_Callback; this.m_ExtraData = p_ExtraData; } /// <summary>
        /// 用户编号 /// </summary>
        public string LoginID { get { return m_LoginID; } set { m_LoginID = value; } } /// <summary>
        /// 发送消息的内容,暂时未使用到 /// </summary>
        public string Content { get { return m_Content; } set { m_Content = value; } } #region IAsyncResult 成员

        public object AsyncState { get { return null; } } public WaitHandle AsyncWaitHandle { get { return null; } } public bool CompletedSynchronously { get { return false; } } public bool IsCompleted { get { return m_IsCompleted; } } #endregion

        /// <summary>
        /// 向客户端响应消息 /// </summary>
        /// <param name="data"></param>
        public void Send(object data) { try { m_Context.Response.Write(this.Content); if (m_Callback != null) { m_Callback(this); } } catch { } finally { m_IsCompleted = true; } } } }
复制代码

MessageHandler.cs

View Code

复制代码
using System; using System.Collections; using System.Collections.Generic; using System.Web; using System.Text; namespace CometSample { public class WebIMMessageHandler { private static readonly WebIMMessageHandler m_Instance = new WebIMMessageHandler(); //记录所有请求的客户端
        List<WebIMClientAsyncResult> m_Clients = new List<WebIMClientAsyncResult>(); //Dictionary<string,WebIMClientAsyncResult> m_Clients=new Dictionary<string,WebIMClientAsyncResult>();
        string m_Users = string.Empty; public WebIMMessageHandler() { } public static WebIMMessageHandler Instance() { return m_Instance; } /// <summary>
        /// 登录 /// </summary>
        /// <param name="p_LoginID"></param>
        /// <param name="p_ClientAsyncResult"></param>
        public void Login(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult) { bool _Logined = false; foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_LoginID) { p_ClientAsyncResult.Content = "你已登录"; _Logined = true; break; } } if (!_Logined) { //m_Clients.Add(p_ClientAsyncResult);
                p_ClientAsyncResult.Content = "OK"; } p_ClientAsyncResult.Send(null); } private string GetUsers() { /* string _Users = string.Empty; foreach (WebIMClientAsyncResult _Item in m_Clients) { _Users += _Item.LoginID + ","; } return _Users; */

            var sbUsers = new StringBuilder(); sbUsers.Append("Users:"); foreach (WebIMClientAsyncResult _Item in m_Clients) { sbUsers.Append(_Item.LoginID); sbUsers.Append(","); } return sbUsers.ToString(); } public void Logout(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult) { foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_LoginID) { m_Clients.Remove(_Item); break; } } p_ClientAsyncResult.Content = "退出成功"; p_ClientAsyncResult.Send(null); //UpdateUserList();

            string _Users = GetUsers(); foreach (WebIMClientAsyncResult _Item in m_Clients) { _Item.Content = _Users; _Item.Send(null); } m_Clients.Clear(); } public void GetUserList(WebIMClientAsyncResult p_ClientAsyncResult) { Connect(p_ClientAsyncResult); string _Users = GetUsers(); foreach (WebIMClientAsyncResult _Item in m_Clients) { _Item.Content = _Users; _Item.Send(null); } m_Clients.Clear(); } public void Connect(WebIMClientAsyncResult p_Client) { bool _Exists = false; foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_Client.LoginID) { _Exists = true; break; } } if (!_Exists) { m_Clients.Add(p_Client); } } /* public void UpdateUserList() { string _Users = GetUsers(); foreach (WebIMClientAsyncResult result in m_Clients) { result.Content = m_Users; result.Send(null); } m_Clients.Clear(); }*/

        /// <summary>
        /// 广播消息 /// </summary>
        /// <param name="p_Message"></param>
        /// <param name="p_AsyncResult"></param>
        public void AddMessage(string p_Message, WebIMClientAsyncResult p_ClientAsyncResult) { //保持连接
            if (p_Message == "-1") { m_Clients.Add(p_ClientAsyncResult); } else { //将当前请求的内容输出到客户端
                p_ClientAsyncResult.Content = p_Message; p_ClientAsyncResult.Send(null); //否则将遍历所有已缓存的client,并将当前内容输出到客户端
                foreach (WebIMClientAsyncResult result in m_Clients) { //发送给所有已经登录用户
                    var strMsg = string.Format("{0}{1}{2}{3}{4}",p_ClientAsyncResult.LoginID,"发送给",result.LoginID,"的消息:",p_Message); //result.Content = p_Message;
                    result.Content = strMsg; result.Send(null); //发送给指定用户
                    /* if (string.Equals(result.LoginID, "ZhangShan") && !string.Equals(p_ClientAsyncResult.LoginID, "ZhangShan")) { var strMsg = string.Format("{0}{1}{2}{3}{4}{5}","Msgs:", p_ClientAsyncResult.LoginID, "发送给", result.LoginID, "的消息:", p_Message); //result.Content = p_Message; result.Content = strMsg; result.Send(null); } */ } //清空所有缓存
 m_Clients.Clear(); } } } }
复制代码

Login.js

View Code

复制代码
/// <reference path="jquery-1.3.2.min.js" >
$(document).ready(function () { //登录,登录成功后,获取在线用户列表,
    function login() { //增加页面跳转
        var strUrl = '/SendInfo.aspx?strUid=' + $("#txtLoginID").val(); window.open(strUrl); } $("#btnLogin").click(function () { if ($("#txtLoginID").val() == '') alert('空'); login(); }); })
复制代码

WebIM.js

View Code

复制代码
/// <reference path="jquery-1.3.2.min.js" > //$(document).ready(function () {

    //状态,代表是否登录
    //var _logined = false;

    //登录,登录成功后,获取在线用户列表,
    function login() { //$.post("comet_broadcast.asyn", { action: 'login', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'login', uid: strUid }, function (data, status) { if (data == "OK") { _logined = true; getuserlist(); //增加页面跳转
                /*var strUrl = '\SendInfo.aspx?strUid=' + $("#txtLoginID").val(); window.open(strUrl); */ } else { alert(data); } }); } //获取在线用户列表,获取列表后,进入消息等待
    function getuserlist() { //$.post("comet_broadcast.asyn", { action: 'getuserlist', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'getuserlist', uid: strUid }, function (data, status) { //alert('getuserlist' + data);
            var result = $("#divResult"); result.html(result.html() + "<br/>" + "用户列表:" + data); wait(); }); } //退出
    function logout() { //$.post("comet_broadcast.asyn", { action: 'logout', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'logout', uid: strUid }, function (data, status) { _logined = false; alert(data); } ); } //消息等待,接收到消息后显示,发起下一次的消息等待
    function wait() { //$.post("comet_broadcast.asyn", { action: 'connect', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'connect', uid: strUid }, function (data, status) { /* var result = $("#divResult"); result.html(result.html() + "<br/>" + "用户列表:" + data); */

               //2.窗口
               new Ext.ux.ToastWindow({ title: '提示窗口', html: data, iconCls: 'error' }).show(document); //服务器返回消息,再次建立连接
               if (_logined) { wait(); } }, "html"); } /*********** *********************消息发送部分*************************** ************/

    function send() { //$.post("comet_broadcast.asyn", { action: 'sendmsg', uid: $("#txtLoginID").val(), content: $("#content").val() },
        $.post("comet_broadcast.asyn", { action: 'sendmsg', uid: strUid, content: $("#content").val() }, function (data, status) { /* var result = $("#divResult"); result.html(result.html() + "<br/>" + "已发消息:" + data); */

            //发送方页面提示
            //潜规则:暂时不处理
            /* //2.窗口 new Ext.ux.ToastWindow({ title: '提示窗口', html: data, iconCls: 'error' }).show(document); */ }, "html" ); //向comet_broadcast.asyn发送请求,消息体为文本框content中的内容,请求接收类为AsnyHandler
        //$.post("comet_broadcast.asyn", { content: $("#content").val() });

        //清空内容
        $("#content").val(""); }; /** * 获取字符串中某个特殊字符首次出现的位置之前的子串 */
    function GetSubStrBySpecChar(strConnStr,strSplit){ var arrStr = strConnStr.split(strSplit); var strSubStr = arrStr[0]; return strSubStr; }
复制代码

Default.aspx

View Code

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CometSample._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="Scripts/Login.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="帐号"></asp:Label>
        <input id="txtLoginID" type="text" />
        <input id="btnLogin" type="button" value="Login" />
        <br />
        <div id="divUserList">
        </div>
    </div>
    </form>
</body>
</html>
复制代码

SendInfo.aspx

View Code

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SendInfo.aspx.cs" Inherits="CometSample.SendInfo" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>SendInfo</title>
    <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="Scripts/WebIM.js" type="text/javascript"></script>

    <link href="Scripts/ext-3.4.0/resources/css/ext-all.css" rel="stylesheet" type="text/css" />
    <script src="Scripts/ext-3.4.0/adapter/ext/ext-base.js" type="text/javascript"></script>
    <script src="Scripts/ext-3.4.0/ext-all.js" type="text/javascript"></script>
    <script src="Scripts/ToastWindow.js" type="text/javascript"></script>

    <script language="javascript" type="text/javascript">

        var strUid = "<%=strUid %>"; $(document).ready(function () { //状态,代表是否登录
            var _logined = false; //alert(strUid);
            //getuserlist_send();
 login(); $("#btnSend").click(function () { send(); }) $("#content").keypress(function (e) { var keyCode = null; if (e.which) keyCode = e.which; else if (e.keyCode) keyCode = e.keyCode; if (keyCode == 13) { send(); return false; } return true; }); }) </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <div id="divUserList">
        </div>
        <br /> 广播内容: <input type="text" id="content" /><br /> 消息记录: <div id="divResult">
        </div>
        <input type="button" id="btnSend" value="广播" />
    </div>
    <div>
        <input id="btnLogout" type="button" value="注销" onclick="logout();"/></div>
    </form>
</body>
</html>
复制代码

最后还需要关注的是配置文件中的路径

在web.config 文件的system.web之间加上

<httpHandlers>
            <add path="comet_broadcast.asyn" type="CometSample.WebIMAsyncHandler" verb="POST,GET"/>
        </httpHandlers>

 

好了运行程序,

效果如下:

登陆之后,跳转到sendinfo页面

 

笔者打开连个浏览器,模拟两个客户端登陆,并且模拟广播消息(能够广播,那么向指定客户端发消息也就很容易了)

我们可以看到在页面右下角,有消息弹出

在.NET WebForm下笔者实现了客户端之间即时消息的推送,但是在.NET MVC 2 下遇到了一些问题,因为mvc框架下对 ,NET WebForm中某些东西不支持。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏