继上次发了一篇博客,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的类"/>