• ASP.NET 实现 Comet 反向 Ajax


    概念:

               Comet 是基于 HTTP长连接的“服务器推”技术,是一种新的 Web 应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,

    而不需要客户端显式的发出请求。Comet 架构非常适合事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和 Web 版在线游戏等。

    //////////////////////////////////////////////////////////////////////////////

    演示示例: 1.分别在两个不同的浏览器打开Sender.aspx页面,分别输入不同的用户名登录。 2.输入收件人的名字和消息内容,点击发送按钮。

    //////////////////////////////////////////////////////////////////////////////

    好了,废话不多说了,我们开始建项目,首先建立一个文件夹重命名为“CSASPNETReverseAJAX”,打开VS 2012 >文件>新建>网站>ASP.NET 空网站,Web位置选择刚才创建的文件夹CSASPNETReverseAJAX


    1,添加一个Message.cs类,代码如下:

    /****************************** 模块标题 ******************************\
    * 模块名称:    Message.cs
    * 项目:        CSASPNETReverseAJAX
    * 消息类包含所有必需的字段在一个消息包。
    *
    \*****************************************************************************/

    namespace CSASPNETReverseAJAX {  
      /// <summary>    
      /// 这是一个实体类,代表一个信息项。    
      /// </summary>    
          public class Message     {        
           /// <summary>        
           /// 这个名字谁将接收这个消息。        
           /// </summary>        
               public string RecipientName { get; set; }

                  /// <summary>       
                  /// 消息内容。        
                 /// </summary>      
               public string MessageContent { get; set; }   
         }
    }

    2. 添加Client.cs类,Client.cs类代表一个客户端,可以从服务器接收消息。同时服务器可以发送消息给客户端。这个类包含两个私有成员和两个公共方法。
    代码如下:

    /****************************** 模块标题 ******************************\
    * 模块名称:    Client.cs
    * 项目:        CSASPNETReverseAJAX
    * 客户端类用于同步消息发送和接收的消息。
    * DequeueMessage方法被调用时,该方法将等到一个新消息
    *
    \*****************************************************************************/

    using System.Collections.Generic;
    using System.Threading;

    namespace CSASPNETReverseAJAX {    
    /// <summary>    
    /// 这个类代表一个web客户端可以接收消息。    
    /// </summary>     
         public class Client     {       
                  private ManualResetEvent messageEvent = new ManualResetEvent(false);        
                  private Queue<Message> messageQueue = new Queue<Message>();
                  /// <summary>        
                  /// //EnqueueMessage方法是专为发送方发送一条信息客户端。        
                  /// </summary>        
                  /// <param name="message">新消息</param>       
                 public void EnqueueMessage(Message message)       
                  {     
                   lock (messageQueue)           
                     {               
                       messageQueue.Enqueue(message);
                       // 设置一个新的消息事件。            
                       messageEvent.Set();        
                     }      
                 }
                 /// <summary>        
                 /// DequeueMessage方法是专为收件人接收消息。        
                 /// 如果没有消息,它会等待,直到一个新的消息插入。         
                 /// </summary>        
                 /// <returns>未读消息</returns>        
                 public Message DequeueMessage()        
                  {    
                    // 等到一个新消息。         
                    messageEvent.WaitOne();
                      lock (messageQueue)           
                       {
                         if (messageQueue.Count == 1)          
                            {
                               messageEvent.Reset();            
                            }                
                         return messageQueue.Dequeue();       
                       }        
                   }    
              }
         }

    3.添加 ClientAdapter.cs类,ClientAdapter.cs类是用于管理多个客户。表示层可以很容易地调用其方法来发送和接收消息。
    代码如下:

    /****************************** 模块标题 ******************************\
    * 模块名称:    ClientAdapter.cs
    * 项目:        CSASPNETReverseAJAX
    * ClientAdapter类管理多个客户端实例。 表示层
    * 调用它的方法来轻松地发送和接收消息。
    *
    \*****************************************************************************/

    using System.Collections.Generic;

    namespace CSASPNETReverseAJAX {    
    /// <summary>    
    /// 这个类是用来发送消息到多个客户端事件。    
    /// </summary>    
     public class ClientAdapter    
     {        
       /// <summary>        
       /// 收件人列表。        
       /// </summary>        
       private Dictionary<string, Client> recipients = new Dictionary<string,Client>();
            /// <summary>
            /// 发送一个消息到一个指定的收件人。
            /// </summary>
            public void SendMessage(Message message)
            {
                //判断如果收件人列表包含收件人就调用client.EnqueueMessage方法发送給他
                if (recipients.ContainsKey(message.RecipientName))
                {
                    Client client = recipients[message.RecipientName];

                    client.EnqueueMessage(message);
                }
            }

            /// <summary>
            /// 被一个收件人等和接收一个消息。
            /// </summary>
            /// <returns>消息内容</returns>
            public string GetMessage(string userName)
            {
                string messageContent = string.Empty;
                //判断收件人列表是否包userName
                if (recipients.ContainsKey(userName))
                {
                    Client client = recipients[userName];

                    messageContent = client.DequeueMessage().MessageContent;
                }

                return messageContent;
            }

            /// <summary>
            /// 加入一个用户到收件人列表。
            /// </summary>
            public void Join(string userName)
            {
                recipients[userName] = new Client();
            }

            /// <summary>
            /// 单例模式.
            /// 这种模式将确保只有一个这个类的实例的系统。
            /// </summary>
            public static ClientAdapter Instance = new ClientAdapter();
            private ClientAdapter(){ }
        }
    }

    4. 添加一个Web服务Dispatcher.asmxDispatcher.asmx 是web服务设计的调用Ajax来接收消息。
    Dispatcher.asmx.cs代码如下:

    /****************************** 模块标题 ******************************\
    * 模块名称:    Dispatcher.asmx.cs
    * 项目:        CSASPNETReverseAJAX
    * 这个web服务的设计被称为Ajax客户端。
    *
    \*****************************************************************************/

    using System.Web.Services;

    namespace CSASPNETReverseAJAX
    {
        /// <summary>
        /// 这个web服务包含的方法帮助事件分发给客户端。
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        [System.Web.Script.Services.ScriptService]
        public class Dispatcher : System.Web.Services.WebService
        {
            /// <summary>
            /// 调度新消息事件。
            /// </summary>
            /// <param name="userName">The loged in user name</param>
            /// <returns>消息内容</returns>
            [WebMethod]
            public string WaitMessage(string userName)
            {
                return ClientAdapter.Instance.GetMessage(userName);
            }
        }
    }
    5. 添加Sender.aspx页面,
    Sender.aspx前台页面代码如下:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Sender.aspx.cs" Inherits="CSASPNETReverseAJAX.Sender" %>

    <!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>
    </head> <body>
        <form id="form1" runat="server">
        <!-- 登录 -->     <asp:Label ID="Label1" runat="server" ForeColor="Red" Text="请先登录:"></asp:Label><br />
        用户名<asp:TextBox ID="tbUserName" runat="server"></asp:TextBox>
        <asp:Button ID="btnLogin" runat="server" Text="登录" onclick="btnLogin_Click" />

        <!-- 接收信息 -->     <asp:ScriptManager ID="ScriptManager1" runat="server" AsyncPostBackTimeout="2147483647">
            <Services>
                <asp:ServiceReference Path="~/Dispatcher.asmx" />
            </Services>
        </asp:ScriptManager>
        <script type="text/javascript">

            // 这个方法将会持续一个http请求,等待消息。
            function waitEvent() {

                CSASPNETReverseAJAX.Dispatcher.WaitMessage("<%= Session["userName"] %>",
                function (result) {

                    displayMessage(result);

                    // 保持循环.
                    setTimeout(waitEvent, 0);
                }, function () {

                    // 保持循环.
                    setTimeout(waitEvent, 0);
                });
            }

            // 附加一个消息内容到结果面板.
            function displayMessage(message) {
                var panel = document.getElementById("<%= lbMessages.ClientID %>");

                panel.innerHTML += currentTime() + ": " + message + "<br />";
            }

            // 返回当前时间字符串.
            function currentTime() {
                var currentDate = new Date()
                return currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();
            }
        </script>

        <h3>消息:</h3>     <asp:Label ID="lbMessages" runat="server" ForeColor="Red"></asp:Label>     <br /><br />

        接收人姓名:<br />     <asp:TextBox ID="tbRecipientName" runat="server" Width="100px"></asp:TextBox><br />

        消息:<br />     <asp:TextBox ID="tbMessageContent" runat="server" Width="300px"></asp:TextBox><br />

        <asp:Button ID="btnSend" runat="server" Text="发送" onclick="btnSend_Click" />
            <br />
            <br /> <asp:Label ID="lbNotification" runat="server" ForeColor="Red"></asp:Label>
        </form>
      </body>
    </html>

    Sender.aspx.cs后台代码

    /****************************** 模块标题 ******************************\
    * 模块名称:    Sender.aspx.cs
    * 项目:        CSASPNETReverseAJAX
    *
    * 用户将使用这个页面送一条消息给一个特定的收件人。
    *
    *
    \*****************************************************************************/

    using System;

    namespace CSASPNETReverseAJAX {
        public partial class Sender : System.Web.UI.Page
        {
            //发送消息事件
            protected void btnSend_Click(object sender, EventArgs e)
            {
                // 创建一个消息实体包含所有必要的数据
                Message message = new Message();
                //从前台页面文本框获取姓名
                string Name = tbRecipientName.Text.Trim();
                //判断姓名不为空或不为null
                if (!string.IsNullOrEmpty(Name))
                {
                    //将姓名赋值給message.RecipientName
                    message.RecipientName = Name;
                    //从前台页面获取文本框消息内容并赋值給message.MessageContent
                    message.MessageContent = tbMessageContent.Text.Trim();
                    //判断消息接收人姓名不为Null或空白字符 且 消息内容不为空或不为null
                    if (!string.IsNullOrWhiteSpace(message.RecipientName) && !string.IsNullOrEmpty(message.MessageContent))
                    {
                        // 调用客户端适配器立即发送消息給特定收件人。
                        ClientAdapter.Instance.SendMessage(message);

                        // 用lable显示一个消息发送的当前时间.
                        lbNotification.Text += DateTime.Now.ToLongTimeString() + ": 消息已发送!<br/>";
                    }
                }
            }
            //登录事件
            protected void btnLogin_Click(object sender, EventArgs e)
            {
                //获取页面用户名文本框
                string userName = tbUserName.Text.Trim();

                // 判断用户名不为空或null
                if (!string.IsNullOrEmpty(userName))
                {
                    //加入一个用户名到收件人列表
                    ClientAdapter.Instance.Join(userName);
                    //用Session保存用户名
                    Session["userName"] = userName;
                }
                else
                {
                    //否则调用js弹窗提示“用户名不正确!”
                    ClientScript.RegisterStartupScript(this.GetType(), "msg", "alert('用户名不正确!')", true);
                }
            }

            protected void Page_PreRender(object sender, EventArgs e)
            {
                // 激活JavaScript等待循环。
                if (Session["userName"] != null)
                {
                    string userName = (string)Session["userName"];

                    //后台调用JavaScript方法waitEvent()开始等待循环。
                    ClientScript.RegisterStartupScript(this.GetType(), "ActivateWaitingLoop", "waitEvent();", true);
                    //前台lable显示正在等待新的消息
                    lbNotification.Text = string.Format("你的用户名是: <b>{0}</b>. 现在正在等待新的消息.", userName);

                    // 禁用登录。
                    tbUserName.Visible = false;
                    btnLogin.Visible = false;
                }
            }
        }
    }

    重新生成一下,没有报错的话我们就可以开始测试了。在IE浏览器打开Sender.aspx页面,打开HttpWatch开始监测浏览器, 输入用户名“张三” 点击登录,
    可以从HttpWatch看到已经开始运行js方法waitEvent()等待消息、,不要关闭页面,
    再从火狐浏览器打开Sender.aspx页面,输入用户名“李四” 点击登录,输入接收人姓名“张三”,输入消息“你好,我是李四!”,点击发送,
    我们再回到IE浏览器的Sender.aspx页面就可以收到“17:13:21: 你好,我是李四!”   
    基本上我们的示例到这里已经成功了!如有写的不好的地方欢迎大家指出。

  • 相关阅读:
    Format用法总汇
    packed record与record区别
    将实数取整函数
    取鼠标所在位置对应的窗口句柄
    Delphi中优秀的字符串分割函数
    Jscript中的FSO对象模式
    关于.NET开发中遇到的一个验证视图状态Mac失败的解决方法随笔
    如何延长电脑硬盘的使用寿命
    如何避免U盘中毒
    如何优化Windows XP系统来加快网速
  • 原文地址:https://www.cnblogs.com/Yashull/p/3010523.html
Copyright © 2020-2023  润新知