转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 站长学院 >> Web开发 >> 正文
在 WinForm 中完整支持在多级目录中保存的 ASP.NET (转)         ★★★★

在 WinForm 中完整支持在多级目录中保存的 ASP.NET (转)

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1741 更新时间:2009/4/23 10:45:51
大概半年前曾写过一个在 WinForm 程序中嵌入 ASP.NET 的简单例子,《在WinForm程序中嵌入ASP.NET》。因为是试验性质的工作,所以当时偷懒直接使用系统自带的 SimpleWorkerRequest 完成 ASP.NET 页面请求的处理工作。使用自带工具类在实现上虽然简单,但受到系统的诸多功能限制,如后面有朋友提到无法直接处理多级子目录的问题等等。(如虚拟目录为 "/" 时无法处理 "/help/about.aspx" 类型的页面请求)
    对于此类需求,一个最好的实现实例就是 www.asp.net 提供的 Cassini。这个例子完整地演示了如何实现一个支持 ASP.NET 的简单 Web 服务器功能,并被 Borland 的 Delphi.NET 等许多开源项目,当作调试用 Web 服务器。虽然只有几十 K 的源代码,但麻雀虽小五脏俱全,还是非常值得一看的。但因为 Cassini 是为处理 Web 服务而设计,因此需要在了解其结构的基础上,做一些定制来满足我们的需求。

    首先来看看 Cassini 的程序结构。

    与我前文例子中采用的结构类似,Cassini 包括界面(CassiniForm)、服务器(Server)、宿主(Host)和请求处理器(Request)等几个主要部分,并通过 Connection 等几个工具类,完成 Web 请求的解析与应答功能。

    总体工作流程图如下:
以下内容为程序代码:

    +-------+ [1] +-------------+ [2] +--------+
    | Admin |---->| CassiniForm |---->| Server |
    +-------+     +-------------+     +--------+
                                          | [3]
                                          V
                       +--------+ [4] +------+
                       | Client |---->| Host |
                       +--------+     +------+
                           ^              | [5]
                           |              V
                           |        +------------+ [6] +---------+
                        [7]|        | Connection |---->| Request |--+
                           |        +------------+     +---------+  | [7]
                           +----------------------------------------+

    [1] Cassini 的管理者(Admin)首先通过 CassiniForm 的界面,设定 Web 服务器端口、页面物理目录和虚拟目录等配置信息;
    [2] 然后以配置信息构造 Server 对象,并调用 Server.Start 方法启动 Web 服务器;
以下内容为程序代码:

public class CassiniForm : Form
{
  private void Start()
  {
    // ...
    try {
        _server = new Cassini.Server(portNumber, _virtRoot, _appPath);
        _server.Start();
    }
    catch {
      // 显示错误信息
    }
    // ...
  }
}

    [3] Server 对象在建立时,将获取或自动初始化 ASP.NET 的注册表配置。这个工作是通过 Server.GetInstallPathAndConfigureAspNetIfNeeded 方法完成的。工作原理是通过 HttpRuntime 所在 Assembly (System.Web.dll) 的版本获得合适的 ASP.NET 版本;然后从注册表中查询 HKEY_LOCAL_MACHINESOFTWAREMicrosoftASP.NET 下是否有正确的 ASP.NET 的安装路径;如果有则返回之;否则会根据 System.Web.dll 的版本,以及 HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFramework 下 .NET Framework 按照目录等信息,动态构造一个合适的 ASP.NET 注册表配置。进行这个工作的原因是 ASP.NET 可以在按照 .NET Framework 后,使用 aspnet_regiis.exe 手工注销掉,而运行支持 ASP.NET 的 Web 服务器,又必须有合适的设置。
    在完成配置和 ASP.NET 安装路径后,Server 将建立并配置 Host 对象作为 ASP.NET 的宿主。
以下内容为程序代码:

public class Server : MarshalByRefObject
{
  private void CreateHost() {
    _host = (Host)ApplicationHost.CreateApplicationHost(typeof(Host), _virtualPath, _physicalPath);
    _host.Configure(this, _port, _virtualPath, _physicalPath, _installPath);
  }

  public void Start() {
    if (_host != null)
        _host.Start();
  }
}

    [4] Host 类作为 ASP.NET 的宿主类,主要完成三部分工作:配置 ASP.NET 的运行时环境、响应客户端(Client)发起的 Web 页面请求、以及判断客户端请求的有效性。
    配置 ASP.NET 的运行时环境主要工作是,为 ASP.NET 的执行和后面请求有效性的判断获取足够的配置信息。例如 Server 能够提供的 Web 服务端口、页面虚拟路径、页面物理路径以及 ASP.NET 程序安装路径等等,以及 Host 根据这些信息计算出的 ASP.NET 客户端脚本的虚拟和物理路径等等。此外还会接管线程所在 AppDomain 的卸载事件 AppDomain.DomainUnload,在 Web 服务器停止的时候自动终止 Web 服务。
    响应客户端(Client)发起的 Web 页面请求功能,是通过建立 Socket 监听 Server 对象指定的 Web 服务 TCP 端口来完成的。Host.Start 方法建立 Socket,并通过线程池异步调用 Host.OnStart 方法在后台监听请求;Host.OnStart 方法则在 接收到 Web 请求后,通过线程池异步调用 Host.OnSocketAccept 方法完成请求的响应工作;Host.OnSocketAccept 则负责在处理 Web 请求的时候,建立 Connection 对象,并进一步调用 Connection.ProcessOneRequest 方法处理 Web 请求。虽然 Host 没有使用复杂的请求分配算法,但因为线程池的灵活使用,使得其性能完全不受处理瓶颈的限制,也是线程池使用的良好范例。
以下内容为程序代码:

internal class Host : MarshalByRefObject
{
  public void Start() {
    if (_started)
      throw new InvalidOperationException();

    // 建立 Socket 监听 Web 服务端口
    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    _socket.Bind(new IPEndPoint(IPAddress.Any, _port));
    _socket.Listen((int)SocketOptionName.MaxConnections);

    _started = true;
    ThreadPool.QueueUserWorkItem(_onStart); // 通过线程池异步调用
  }

  private void OnStart(Object unused) {
    while (_started) {
      try {
        Socket socket = _socket.Accept(); // 响应客户端请求
        ThreadPool.QueueUserWorkItem(_onSocketAccept, socket); // 通过线程池异步调用
      }
      catch {
        Thread.Sleep(100);
      }
    }
    _stopped = true;
  }

  private void OnSocketAccept(Object acceptedSocket) {
    Connection conn =  new Connection(this, (Socket)acceptedSocket);
    conn.ProcessOneRequest(); // 处理客户端请求
  }
}

    最后,判断客户端请求的有效性的功能,是通过三个重载的 Host.IsVirtualPathInApp 方法,提供给 Connection 在具体处理客户端请求时调用,来判断请求的有效性,下面讨论 Connection 时再详细解释。

    [5] Host 在建立 Connection 对象并调用其 ProcessOneRequest 方法处理用户请求时,Connection 对象会首先等待客户端请求数据(WaitForRequestBytes),然后创建 Request 对象,并调用 Request.Process 方法处理请求。而其自身,则通过一堆 WaitXXX 函数,为 Request 类提供支持。
以下内容为程序代码:

internal class Connection {
  public void ProcessOne

[1] [2] [3]  下一页


[C语言系列]C# WinForm 中Label自动换行 解决方法  [电脑应用]c# winform 打包部署 自定义界面 或设置开机启动
[电脑应用]C# WinForm 关闭登陆窗体,打开主窗体的实现  [C语言系列]winform datagridview如何获取选中行的索引
[C语言系列]c# _winform实现网页上用户自动登陆,模拟网站登录  [C语言系列]C#的winform中实现tabPage的隐藏 .
[C语言系列]C# WinForm中Application.StartupPath与AppDomain…  [系统软件]WinForm 程序实现XP风格
[常用软件]双剑合璧 在Win XP下刻录音乐CD  [VB.NET程序]使用VB.Net做一个配置web.config功能的WinForm(原…
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · Web开发  · 网页制作
    · 平面设计  · 网站运营
    · 网站推广  · 搜索优化
    · 建站心得  · 站长故事
    · 互联动态
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台