使用IHttpAsyncHandler实现服务器推送技术

来源:互联网 发布:如何检测域名被墙 编辑:程序博客网 时间:2024/06/05 09:35

继上次发了一篇博客,ajax的应用以来,这是本菜鸟在博客园的第二篇文章.

由于第一篇博客,大家反映是会的没用,不会的嫌多.那么,这篇博客,不会又丑又长的.只是会简单介绍服务器推模型的好处,以及我自己使用中发现的问题..

我希望大家看了这篇博客,一定要看完,并不是写的多好,因为最后 我会给出web.config的配置节点代码,如果会自己配置的当我没说.

先啰嗦几句话. 在我不会推模型之前,我一直都是拉模型,也就是让js代码每隔一段时间向服务器索取数据,并刷新,当然,肯定是异步刷新..

今天看了看推模型,并写了简单的代码.不多说,如果会拉模型的,感觉感觉comet的妙处吧..

由于本次代码全是手写,不保证没错

<由于几个类都是实现接口,通过配置文件,实现htm页面访问,所以还是看完吧>

(创建一个项目,asp.net web项目.然后创建一个类,继承自IHttpHandler接口,)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace Comet

{

//继承并实现了 IHttpHandler   接口

  public class MyHandler : IHttpHandler  

    {       

//这个属性,和方法 都是实现 IHttpHandler 的

    public bool IsReusable  

        {          

      get { return true; }   

       }

         public void ProcessRequest(HttpContext context)     

     {      

//设置不让客服端缓存

        context.Response.Cache.SetCacheability(HttpCacheability.NoCache);     

         List<MyAsyncResult> userlist = MyAsyncHandler.Queue;

            string sessionId = context.Request.QueryString["sessionId"];    

          string message = context.Request.QueryString["message"];

            foreach(MyAsyncResult res in userlist)           

    {

//如果不是自己就推

                 if (res.SessionId != sessionId)       

          {              

      //激发callback,结束请求     

         res.Message = message;                   

                 res.SetCompleted(true);                 

       }

            }

         }

    }

}

(接着第二个类,实现IHttpAsyncHandler接口)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace Comet

{

  public class MyAsyncHandler : IHttpAsyncHandler

{

//这个集合 用于存放 所有请求的

  public static List<MyAsyncResult> Queue = new List<MyAsyncResult>();

  public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)

{

   context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

string sessionId = context.Request.QueryString["sessionId"];

//查找Queue这个集合  SessionId ==传过来的sessionId  !=null

if (Queue.Find(q => q.SessionId == sessionId) != null)

{

int index = Queue.IndexOf(Queue.Find(q => q.SessionId == sessionId));

//把HttpContext对象的实例等于当前请求的所有信息

Queue[index].Context = context;

Queue[index].CallBack = cb;

return Queue[index];

}

//MyAsyncResult 这个类是 回调的参数类(相当于 你定义一个事件 使用的泛型的   public event EventHandler<MyEvargs> Events;  MyEvargs这个类继承了EventArgs  同样的道理)

MyAsyncResult asyncResult = new MyAsyncResult(context, cb, sessionId);

Queue.Add(asyncResult);

return asyncResult;

}

这个方法是这个异步接口的另一个方法

  public void EndProcessRequest(IAsyncResult result) 

       {         

   MyAsyncResult rslt = (MyAsyncResult)result;     

//向别的客服端推送  某个 客服端发送的 信息

      rslt.Context.Response.Write(rslt.Message);     

       rslt.Message = string.Empty;      

  }

//为什么不实现这个方法  (因为IhttpAsyncHandler接口继承了IHttpHandler这个接口,所以实现接口的时候,就实现了它,但是 我们不管它)

  #region IHttpHandler 成员 不实现

        public bool IsReusable     

   {         

   get { return true; }   

     }

        public void ProcessRequest(HttpContext context)     

   {

        }

        #endregion

}

}

下面是参数类,这个类 比较简单 但是 所有的数据 都是经过这些个参数的,回调 才是关键

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace Comet

{

//就是继承了这个IAsyncResult接口,所以就可以是回调的参数类

     public class MyAsyncResult : IAsyncResult   

{      

//这个接口的实现

    public object AsyncState { get; private set; }

        public System.Threading.WaitHandle AsyncWaitHandle { get; private set; }

        public bool CompletedSynchronously { get { return false; }}

        public bool IsCompleted { get; private set; }      

//一些个参数

   public HttpContext Context { get; set; }   

       public AsyncCallback CallBack { get; set; } 

       public string SessionId { get; set; }     

     public string Message { get; set; }

//构造函数

        public MyAsyncResult(HttpContext context, AsyncCallback cb, string sessionId)   

     {           

    this.SessionId = sessionId;        

      this.Context = context;       

       this.CallBack = cb;      

  }

//这个方法对于的是MyHandler调用哪个方法,

//它的主要作用是,用某种浏览器检测工具,也就是能检测所有请求的工具,就能看出,它是结束当前的请求,在用js马上开始另一个请求,好处就是,感觉这个客服端是长连接的

        public void SetCompleted(bool iscompleted)  

      {     

         this.IsCompleted = iscompleted;    

          if (iscompleted && this.CallBack != null)      

          {

                CallBack(this);         

       }

        }

    }

}

//其实到现在 写的差不多了,我们已经实现了IHttpHandler IHttpAsyncHandler 这两个接口,并处理完了,最麻烦的回调,

剩下的就是,通过一个页面,来调用...  等下看配置文件..其实这个配置文件,已经可以实现了伪静态页面...

新建一个htm页面吧 什么名字无所谓了,代码直接 拿过去,配置文件 一定要配置哦,不然 上面的一切都是扯淡...呵呵

//这些代码

<!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>  

  <title></title>

</head>

<body>  

  <input type="text" id="sessionId" /><input type="button" value="进入" onclick="comin()" /><br />   

<input type="text" id="message" /><input type="button" value="发送" onclick="send()" />  

  <div id="messages"></div>   

<script type="text/javascript">

        function comin() {        

    var xmlHttp = ajaxFunction();     

       var url = "MyAsyncHandler.ashx?sessionId=" + document.getElementById("sessionId").value;      

      xmlHttp.onreadystatechange = function() {     

           if (xmlHttp.readyState == 4) {            

        if (xmlHttp.status == 200) {            

            document.getElementById("messages").innerHTML += xmlHttp.responseText + "<br>";       

                 //连接已经结束,马上开启另外一个连接    

//看看这句话 呵呵 感觉像无限的 递归

//服务器的一个推 结束,马上开始 继续 一个请求 等待   

                comin();       

             }         

       }       

     }       

     xmlHttp.open("get", url, true);  

          xmlHttp.send(null);   

     }

        function send() {         

   var xmlHttp = ajaxFunction();  

          var url = "MyHandler.ashx?sessionId=" + document.getElementById("sessionId").value + "&message=" + document.getElementById("message").value;      

      xmlHttp.onreadystatechange = function() {      

          if (xmlHttp.readyState == 4) {          

          if (xmlHttp.status == 200) {

                    }              

      else {               

         alert("服务器端错误");     

               }          

      }       

         else {       

             alert("服务器端错误");   

             }         

   }         

   xmlHttp.open("get", url, true);     

       xmlHttp.send(null);    

    }

        function $$(id) {             return typeof id == String ? document.getElementById(id) : id;         }

        function ajaxFunction() {      

      var xmlHttp;         

   try {          

      xmlHttp = new XMLHttpRequest();  

          }      

      catch (e) {     

           try {               

     xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");     

           }              

  catch (e) {      

              try {   

                     xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");  

                  }               

     catch (e) {              

          alert("您的浏览器不支持AJAX!");     

                   return false;          

          }            

    }         

   }       

     return xmlHttp; 

       }  

    </script>

</body>

</html>

放上配置文件的代码

<不要弄错了,,,找到httpHandlers节点,在里面, </httpHandlers>关闭节点的上面加上我给的代码,不然一切都是扯淡...>

(细讲一行)

<!-- add一个节点 verb="*" 这是一个通配符,相当于在 <authorization>节点配置 <allow users="*"/>它一样   -->

<!--path="MyHandler.ashx" 这个意思是 (上面的ajax  open的没有) 本来就是一个不存在的文件  通过配置文件 连接上的,伪静态页面 就是这样做的  -->

<!-- type="Comet.MyHandler"/ 它的意思是  path这个东西指向的类 -->

  <add verb="*" path="MyHandler.ashx" type="Comet.MyHandler"/> 

       <add verb="*" path="MyAsyncHandler.ashx" type="Comet.MyAsyncHandler"/>

啰嗦一句,伪静态页面的配置

<add verb="*" path="hello.htm,hello.html" type="指向实现了IHttpHandler的类"/>

原创粉丝点击