<marquee width=358>欢迎来到月影社区,希望这里可以成为您美丽的梦幻花园,如果你觉得这里好请分享给您的朋友!- wf66.com</marquee> 将月影社区设置为您的首页将月影社区地址加入到您的收藏栏
月影社区时尚音乐音乐查询IP手机许愿之瓶最新更新文件加密访客留言爱音乐
欢迎您,首页 >> 信息中心 >> 实现自己的ASP.NET宿主系统

请输入您关键字:


实现自己的ASP.NET宿主系统

推荐查看本文HTML版本


一、 宿主概念
托管是.NET的一个很基础的概念,所有的.NET应用程序代码要完全发挥作用需要进入托管的环境(CLR --Common Language Runtime),而这个环境实际上就是称作宿主(Host)为将要启动的.NET代码准备的。目前来讲windows系统上,能够担负这个重任的有3类已存程序:
1、 shell(通常是Explorer),提供从用户桌面启动.NET程序,创建一个进程,启动此进程建立CLR
2、 浏览器宿主(Internet Explorer),处理从web下载的.NET代码执行。
3、 服务器宿主(如IIS的辅助进程ASPnet_wp.exe)
通常来讲,我们开发的ASP.NET的程序运行在IIS的环境下(实际上由一个ISAPI控制启动CLR),但实际上ASP.NET程序可以摆脱IIS单独在任何托管环境下运行。本文讨论了ASP.NET程序如何在自定义的环境中启动,希望有助于我们了解ASP.NET的执行原理,同时使我们开发的ASP.NET能够在任何.NET环境下执行,不管是服务器操作系统还是普通的桌面操作系统。
二、 IIS宿主中ASP.NET的执行分析
关于IIS中ASP.NET的执行细节,很多文章做了详尽权威的分析,本文不打算赘述,在此给出一些参考:
http://www.yesky.com/SoftChannel/72342380468043776/20030924/1731387.shtml
http://chs.gotdotnet.com/quickstart/ASPplus/doc/procmodel.ASPx
这些文章大致重点分析了:宿主环将如何启动、ASP.NET应用程序如何产生程序集、如何加载,同宿主的交互等细节。
三、 构造自己的ASP.NET宿主程序
ASP.NET是作为微软ASP的替代技术出现的,所以我们重点讨论如何通过web方式应用ASP.NET(显然还有其他方式),具体就是:我们用.NET平台的语言编写一个控制台程序,这个程序启动一个ASP.NET应用环境,执行关于ASPx的请求。具体来讲,需要做以下工作:
1、实现一个Web Server,监听所有的web请求,实现Http web hosting
2、启动一个应用程序域,创建一个ASP.NET的ApplicationHost,建立一个ASP.NET的应用程序域,另外还建立一个HttpWorkerRequest的具体实现类,该类可以处理ASPx请求,编译ASPx页,编译后的托管代码缓存入当前应用程序域,然后执行代码,得到执行结果。建议在继续阅读下文前,仔细翻查MSDN中的关于这两个类得参考说明。
System.Web.Hosting.ApplicationHost类用于建立一个独立的应用程序域。当然不是普通的应用程序域,而是为ASP.NET建立执行环境,准备需要的空间、数据结构等。仅有一个静态方法static object CreateApplicationHost(
Type host //具体的用户实现类,就是ASP.NET应用域需要加载的类
string virtualDir, //此应用域在整个web中的执行目录,虚拟目录
string physicalDir //对应的物理目录
);
而其中的host 参数指向一个具体的类,由于该类实际上属于两个应用域之间的联系类,在两个应用程序域之间编组传递数据,所以必须要继承自MarshalByRefObject,以允许在支持应用程序中跨应用程序域边界访问(至于为什么,建议翻查参考3)。
可以看到,我们需要启动两个应用程序域(web server功能应用程序域和ASP.NET 应用程序域),而这两个(应用程序)域之间通过跨(应用程序)域的流对象引用来实现,使得在ASP.NET域中执行的结果可以通过web server域返回给请求者。
可以大致下图表达
执行ASP.NET的Web服务器端

 
 
 
 
WEB客户端
代码实现分析:
using System;
using System.Web ;
using System.Web.Hosting;
using System.IO;
using System.NET;
using System.NET.Sockets ;
using System.Text ;
using System.Threading ;
namespace MyIIS
{
class ASPHostServer
{
[STAThread]
static void Main(string[] args)
{
//创建并启动服务器
MyServer myserver=new MyServer(“/”, ”c:inetpubwwwrootmyWeb”);
}
}
class MyServer //处理HTTP协议的服务器类
{
private ASPDOTNETHost ASPnetHost; //ASP.NET host的实例
private TcpListener mytcp; //Web监听套接字
bool bSvcRunning=true; //服务是否运行指示
FileStream fs; //处理http请求的普通文本要求
public MyServer(string virtualDir ,vstring realPath)
{//在构造函数中启动web监听服务
try
{
mytcp=new TcpListener(8001);
mytcp.Start(); //启动在8001端口的监听
Console.WriteLine("服务启动...");
//利用CreateApplicationHost方法建立一个独立的应用程序域执行ASP.NET程序
ASPnetHost = ( ASPDOTNETHost )ApplicationHost.CreateApplicationHost
( typeof( ASPDOTNETHost ) , virtualDir , realPath);
Thread t=new Thread(new ThreadStart(MainSvcThread));
t.Start(); //服务线程启动 负责处理每一个客户端的请求
}
catch(NullReferenceException)
{
Console.WriteLine("NullReferenceException throwed!") ;
}
}
public void MainSvcThread() //ASP.NET Host的web服务器的主要服务线程
{
int s=0;
string strRequest; //请求信息
string strDir; //请求的目录
string strRequestFile; //请求的文件名
string strErr=""; //错误信息 [月影读书频道 http://wf66.com/]
string strRealDir; //实际目录
string strWebRoot=rpath; //应用根目录
string strRealFile=""; //正在请求的文件的磁盘路径
string strResponse=""; //回应响应缓冲区
string strMsg=""; //格式化响应信息
byte[] bs; //输出字节缓冲区
while(bSvcRunning)
{
Socket sck=mytcp.AcceptSocket(); //每个请求到来
if(sck.Connected)
{
Console.WriteLine("Client {0} connected!",sck.RemoteEndPoint);
byte[] bRecv=new byte[1024]; //缓冲区
int l=sck.Receive(bRecv,bRecv.Length,0);
string strBuf=Encoding.Default.GetString(bRecv); //转换成字符串,便于分析
s=strBuf.IndexOf("HTTP",1);
string httpver=strBuf.Substring(s,8); // HTTP/1.1 之类的
strRequest=strBuf.Substring(0,s-1);
strRequest.Replace("","/");
if((strRequest.IndexOf(".")<1) && (!strRequest.EndsWith("/")))
{
strRequest += "/";
}
s=strRequest.LastIndexOf("/")+1;
strRequestFile = strRequest.Substring(s); strDir=strRequest.Substring(strRequest.IndexOf("/"),strRequest.LastIndexOf("/")-3); //取得访问的URL
if(strDir=="/")
{
strRealDir=strWebRoot;
}
else
{
strDir=strDir.Replace("/","");
strRealDir=strWebRoot + strDir;
}
Console.WriteLine("Client request dir: {0}" , strRealDir);
if(strRequestFile.Length==0)
{
strRequestFile="default.htm"; //缺省文档
}
int iTotlaBytes=0; //总计需要输出的字节
strResponse=""; //输出内容
strRealFile = strRealDir +""+ strRequestFile;
if(strRealFile.EndsWith(".ASPx")) //这里有Bug!!
{
string output="";
//注意我下面的语句们给host对象ProcessRequest方法传递了一个ref类型的参数,
//ASPnetHost会从ASP.NET的执行应用程序域执行一个请求后返回流给当前web server所在的域,这实际上发生了一个域间的调用
ASPnetHost.ProcessRequest (strRequestFile, ref output);//转换成字节流
bs=System.Text.Encoding.Default.GetBytes (output);
iTotlaBytes=bs.Length ; //调用套接字将执行结果返回
WriteHeader(httpver,"text/html",iTotlaBytes,"200 OK",ref sck);
FlushBuf(bs,ref sck);
}
else
{try
{
fs=new FileStream( strRealFile,FileMode.Open,FileAccess.Read,FileShare.Read );
BinaryReader reader=new BinaryReader(fs); //读取
bs=new byte[fs.Length ];
int rb;
while((rb=reader.Read(bs,0,bs.Length ))!=0)
{
strResponse =strResponse +Encoding.Default.GetString(bs,0,rb);
iTotlaBytes =iTotlaBytes+rb;
}
reader.Close();
fs.Close();
WriteHeader(httpver,"text/html",iTotlaBytes,"200 OK",ref sck);
FlushBuf(bs,ref sck);
}
catch(System.IO.FileNotFoundException )
{//假设找不到文件,报告404 WriteHeader(httpver,"text/html",iTotlaBytes,"404 OK",ref sck);
}
}
}
sck.Close(); //Http请求结束
}
}
// WriteHeader想客户端发送HTTP头
public void WriteHeader(string ver,string mime,int len,string statucode,ref Socket sck) {
string buf="";
if(mime.Length ==0)
{
mime="text/html";
buf=buf+ver+ statucode + "rn";
buf=buf+"Server:MyIIS"+"rn";
buf=buf+"Content-Type:"+mime +"rn";
buf=buf+"Accept-Rabges:bytes"+"rn";
buf=buf+"Content-Length:"+ len +"rnrn";
byte[] bs=Encoding.Default.GetBytes(buf);
FlushBuf(bs,ref sck);
}
}
// FlushBuf刷新向客户发送信息缓冲区
public void FlushBuf(byte[] bs,ref Socket sck)
{
int iNum=0;
try
{
if(sck.Connected)
{
if((iNum=sck.Send(bs,bs.Length ,0))==-1)
{
Console.WriteLine("Flush Err:Send Data err");
}
else
{
Console.WriteLine("Send bytes :{0}",iNum);
}
}
else
{
Console.WriteLine("Client diconnectioned!");
}
}
catch(Exception e)
{
Console.WriteLine("Error:{0}",e);
}
}
}
// ASPDOTNETHost类实例需要跨越两个应用程序域,所以继承自MarshalByRefObject
class ASPDOTNETHost:MarshalByRefObject
{
public void ProcessRequest( string fileName ,ref string output)
{
MemoryStream ms=new MemoryStream(); //内存流,当然为了速度
StreamWriter sw = new StreamWriter(ms); //输出
sw.AutoFlush = true; //设为自动刷新 /先构造一个HttpWorkRequest请求类,以便ASP.NET能够分析获取请求信息,同时传入一个输出流对象供ASP.NET执行期间返回html流
HttpWorkerRequest worker = new SimpleWorkerRequest( fileName, "" ,sw) ; // 调度某个页,这里面的包含很多细节,后面分析
HttpRuntime.ProcessRequest( worker ) ;
StreamReader sr= new StreamReader(ms); //准备从内存流中读取
ms.Position =0; //移动指针到头
output = sr.ReadToEnd();
}
}
}
HttpRuntime.ProcessRequest( worker ) ;包括了那些细节呢?大体上如下:
1、首先,worker对象传入给ASP.NET的应用程序域,告知发生了对于哪一个ASPx文件的请求,以及当前目录是什么,如果在执行期间发生的输出内容应该写到哪里(sw对象)。这发生一个由web server当前应用程序域到我们自己建立的ASP.NET应用程序域的跨(应用程序)域调用,还可能由于是第一次访问,会发生了全局事件、或者session事件等。
2、ASP.NET的应用程序域会检测请求的ASPx文件是否存在,不存在,就报错;如果存在还要看看代码缓存中是否存在上次编译的代码,如果存在且ASP.NET检测到不需要重新编译,会直接执行缓存中的代码;如果不存在或者代码过期需要重新编译,就需要读取ASPx文件,编译成.NET的代码,存入缓存。可能有些页存在代码和模板分离成多个文件,甚至包括一些资源文件,这些都需要读取后编译成.NET的虚拟机代码,然后在托管环境里执行。
3、执行ASP.NET的编译代码缓存中的代码,输出数据利用sw对象输出。
当然,根据不同的配置,还有很多方法的调用/事件的发生等细节不同。
如何调试运行以上程序,观察结果呢?
建立一个控制台类型工程,将上述代码录入后编译,将得到的程序拷贝在作为站点应用起始目录(譬如c:inetpubwwwrootmyweb)的bin子目录下,然后启动,这样在其中创建ASP.NET应用程序域才不会因为程序集加载失败而出错。建立一个asp.net工程在目录下,添加default.htm文件和测试用的test.aspx,加入.NET执行代码,然后启动IE,在地址栏分别输入:http://127.0.0.1:8001/default.htm http://127.0.0.1:8001/test.aspx感受一下执行过程。甚至你可以建立的工程中设定断点之类,仔细调试和观察其中的细节。亲手试一试吧,一定有收获的!
四、 自己构造ASP.NET宿主的意义
费了半天劲搞自己的ASP.NET宿主,对于我们有何意义呢?
首先,是大致从代码级清楚分析ASP.NET执行细节,自己学习了解执行细节,除了可以在出现ASP.NET故障可以进行精确定位和排除外,还可以帮助我们在写ASP.NET应用程序时写出更有效率和健壮的代码。
其次,我们可以提供一个思路,可以将我们的ASP.NET程序运行于低配置机器上,脱离IIS。ASP.NET的“原配”宿主IIS需要运行在Server OS上,要知道在安全专家眼中,IIS可是大隐患的源头之一。我们可以将很多传统程序利用ASP.NET编写,但脱离IIS独立执行,譬如在win98系统上执行ASP.NET。web server和ASP.NET都在托管环境中执行,相比较ISAPI建立宿主然后执行,除提高效率外,还可以使用.NET平台提供的丰富管理调控功能,写B/S程序更接近传统程序编写方式,这对于程序员来讲都是效率(编写代码的效率和执行效果效率)的保证。
另外,对于采用ASP.NET做的项目,大家可以很方便进行开发调试、运行维护、安装。即使是普通桌面程序,我们也可以通过类似制作网页的方式编写这些界面和代码,然后独立建立类似本例中的Host环境,根据用户交互请求加载执行某些页面,然后将界面在客户端通过相关组件显示出来。你可以通过此获得ASP.NET的即时编译功能和ASP.NET宿主托管环境,大量可自由使用的API,便于开发、安装、维护。毕竟,托管环境几乎准备了您需要的一切功能。
五、 参考资料
1、.NET MSDN
2、清华大学出版社《.NET网络高级编程》Andrew Krowczyk Viond Kumar原著
3、清华大学出版社《.NET框架程序设计(修订版)》Jsfftry Richter著

实现自己的ASP.NET宿主系统 2006-8-31
转到本主题第:[ 1 ]
相关评论

暂无评论

总计0页 [ ]上一页 下一页
发表评论(揪错)
呢称: * 您尚未登陆,请登录
来自: *
内容:
 

(为防止非法信息,您的言论提交后需要审核才能正常显示)

文学
精品文萃 情感天地 言情小说
网络小说 玄幻小说 悬疑恐怖
武侠小说 古典品谈 外国名著
儿童文学 会员原创 学习园地
杂谈其它
娱乐
爆笑网文 星座占卜 影音动漫
娱乐新闻 影视剧情
诗词
青竹诗歌 个人诗集 宋词雅赏
全唐诗录
新闻
国际新闻 国内新闻 科技新闻
体育新闻
图片
图文专区 艺术长廊 桌面壁纸
精品素材 像素图片
漫画
单幅漫画 爆笑四格 连环漫画
电脑
电脑入门 图形图像 编程开发
游戏
我爱Q宠 最新攻略 最新秘籍
游戏新闻 技巧心得
经济
帕格节电 财经资讯 股市证券
生活
百科知识 外语学院 潮流时尚
健康医疗 宠物花卉 汽车地带
行走天下
美食
面食甜点 家常菜品 药膳食疗
美食天下 烹饪技巧 松辽风味
燕京风味 巴蜀风味 滇黔风味
赣江风味 徽皖风味 闽台风味
齐鲁风味 中州风味 岭南风味
荆楚风味 三晋风味 淞沪风味
苏扬风味 潇湘风味 钱塘风味
民族风味 素斋仿荤
营销
管理杂谈 谈经论道 培训激励
经营战略 职场生涯 公关交际
关于我们版权声明本站导航友情连结作品演示 TOP↑
本论坛言论纯属发表者个人意见,与£月影社区£立场无关。 皖ICP备16024038号-1
禁止发布任何色情/政治/反动相关信息让我们共同来营造一个属于我们的梦幻家园
Copyright ©2001-2006 MoonShadow. All rights reserved.  Version 4.0  Licence 2006.4.2
建站天数:7216天 本站基于ASP+JS构建,完全自主开发,版权归属月影社区 管理员QQ:23165062 Time:718ms