打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Asp.net MVC项目的部署(一):IIS以及Asp.net与IIS相关的部分
userphoto

2013.12.22

关注

Asp.net MVC项目的部署(一):IIS以及Asp.net与IIS相关的部分

         Asp.net MVC 1.0正式发布至今已将近四个月了,想必了解Asp.net MVC的人越来越多。打算写一点关于如何部署Asp.net MVC的文字。

内容包括:IIS的版本变化,Asp.net的工作原理等。

涉及的东西比较基础,内容也比较多,肯定会有我们已经知道的东西,但是为了完整性,可能会分(一)、(二)……如果你对Asp.net不太熟悉的话,可能阅读中会遇到一些理解不了的地方,在这些地方我会给出推荐您阅读的书籍或者园友的文章供你参考,如果你是Asp.net高级开发人员的话可以略过。

主要参考资料:Pro Asp.net MVC Framework.pdf(你可以搜索下载到)

 

部署,就是将你的网站发布到服务器上以使人们可以实际使用。如果你曾经部署过Asp.net项目的话,你将会发现部署Asp.net MVC实际上跟部署 Asp.net差不多,唯一特殊的地方是Asp.net MVC使用到了Routing,可能有人尝试过在IIS6上使用无后缀URL的方法,如果你知道了下面这些列出的内容的话,就会变得很容易了。

l  Asp.net MVC宿主服务器所需的条件。

l  IIS处理请求的架构,路由是如何与之融为一体的。

l  安装IIS67Windows服务器,将Asp.net MVC项目部署在他们上。

l  配置你的Asp.net MVC项目。

该篇包含前两个内容

 

服务器环境

要运行Asp.net MVC项目,我们的服务器需要满足如下条件:

l  IIS5.1或者更高版本的IIS,并且开启了Asp.net服务。

l  .NET Framework 3.5(最好同时安装了SP1

推荐的操作系统是Windows server 2003IIS6)和Windows server 2008IIS7)。Asp.net MVC本身不要求服务器必须安装了它。因为我们将System.Web.Mvc.dll和你或许用到的Microsoft.Web.Mvc.dll直接放在\Bin文件夹中部署就可以了,这种部署方式叫做私有部署,如果你买的空间没有安装Asp.net MVC的话(即GAC中没有上述的两个dll)通过私有部署的方式也很容易,另外如果你的服务器没有安装过.NET Framework SP1的话,你还需要将System.Web.Abstractions.dllSystem.Web.Routing.dll也拷贝到你的\Bin文件夹中。下面会详述这些。

Asp.net MVC对我们买的虚拟服务器有什么样的要求

除了需要服务器支持Asp.net 2.0和安装了.NET Frameworkd 3.5之外没有其他要求。所以我们看不到有空间提供商打广告说自己的空间支持Asp.net MVC,因为通过把相关的程序集放在\Bin文件夹中你同样可以私有部署你的Asp.net MVC项目。

如果你的服务器提供商用的是IIS7,那么IIS7Asp.net的集成管线模式可以给你带来干净的无后缀的URL,如果是IIS6的话虽然也能够做到,但是就没有IIS7那么高效、方便和容易了,下文会有关于Windows server 2003/IIS6的内容。

关于IIS

l  IIS6/ Windows Server 2003

l  IIS7/Windows Server 2008

l  IIS 7.5/Windows Server 2008 R2(尚未发布)。

我们仅仅介绍6.0之后版本的IIS,下面我们来快速覆盖一下IIS的知识,包括:虚拟路径、绑定设置和应用程序池。最后谈一下IIS内部是如何处理请求的(IIS7是如何处理无后缀的URL的)。

理解网站和虚拟目录

IIS可以同时宿主多个不同的网站,我们对每一个网站指定一个根目录,这个目录可以是服务器的本机目录也可以在网络的其他地方,然后IIS就可以从它所管理的那些目录下寻找或获得相应静态或动态请求的内容给我们了。

         为了指导特定的HTTP请求到相应的相应网站,IIS允许我们配置“绑定”。所谓“绑定”就是将一个特定的IPTCP端口号、和HTTP主机名对应到特定的网站。如下图:


说明:Windows7/IIS7.5

         作为一个额外的配置,你还可以在网站目录文件夹任意层级上添加虚拟目录,每一个虚拟目录表示IIS将从其他地方提取或获得内容返回给对该虚拟目录的请求,这取决于你建立的虚拟目录所指定的文件夹的位置(它同样可以在本机也可以在网络的其他地方)。虚拟目录的目的是让真实文件所在的位置与网站目录列表脱离关系,有点类似文件夹的“快捷方式”,虚拟目录的存在使得外界不知道我们的真实文件所在具体位置,个人感觉逻辑上的意义大于安全上的意义。


说明:IIS7/IIS7.5中虚拟目录的显示

对于每一个虚拟目录你还可以选择是否赋予它独立的应用程序地位。如果选择这样做,该虚拟目录对应的独立的应用程序就拥有自己独立的配置文件了,如果该独立的应用程序是个Asp.net应用程序的话,那么它的状态也是独立的啦,是与它的父级应用程序的状态无关的。显然,因为他们是相互独立的应用程序,所以被设置成独立的应用程序的这个虚拟目录中所运行的Asp.net完全可以是和父级不同的版本的Asp.net

IIS6开始,IIS引入了应用程序池(application pools)。应用程序池用来隔离同一台服务器上的多个同时运行的应用程序,每一个应用程序池工作在一个独立的工作进程中,设定相应的最大内存和CPU使用量,进程回收时间表,等。每一个网站或设置为独立应用程序的虚拟目录应用程序都会被分配到建立起来的IIS的应用程序池的其中一个池中去。一般的话,每个应用程序应建立一个应用程序池而不是与其他应用程序共用。这样可以保证如果一个应用程序崩溃了不影响其他应用程序的正常运行。参考:应用程序池

绑定网站到主机名、IP地址和端口

         因为同一个服务器可以宿主多个网站,所以就需要一个系统来分派请求到正确的Web应用程序。上文提到,我们可以绑定网站到一个或者多个:

l  端口号

l  主机名

l  IP地址(仅当服务器有多个IP地址时——比如有多个网络适配器)

对于主机名和IP地址,你可以选择不做任何指定,不做任何指定等于是一个通配符,这样的话对于所有不匹配特定网站的请求就会匹配给它。如果多个网站具有相同的绑定设置的话,同一时间只可能有一个是可用的,其它的处于停掉的状态,否则就不唯一了,对吧。虚拟目录继承父级应用程序的绑定设置。

IIS是如何处理进来的请求并调用ASP.NET

IIS将接收到的一个请求分配给相应的网站的时候,它需要决定怎么来处理这个请求。它是要直接从磁盘返回一个静态内容呢,还是要调用网站应用程序执行它并动态地生成内容来返回呢?它是如何决定这些的?

作为一个Asp.net MVC程序域,你需要理解IIS的这个机制,不仅是Asp.net MVC程序员,Asp.net程序员都需要理解这个机制(Asp.net程序员包含Asp.net MVC程序员)——至少应该有个基本了解;否则,你将会在理解进来的请求与你的路由配置映射时遇到困难。

IIS6IIS7在传统模式下是如何处理请求的

如果你没有使用IIS7的集成管线模式的话,你使用的将是回归到IIS5的传统管道模型。在这个模式下,IIS只能提供静态内容和具有特定扩展名的从而可以映射到相应的ISAPIURL返回的动态内容。

IIS分析请求近来的URL,取得它的扩展名(比如:http://hostname/folder/file.aspx?foo=bar的扩展名是.aspx),将该扩展名发往相应的ISAPI扩展程序。对于IIS6IIS7来说,你都可以配置ISAPI扩展程序与扩展名的映射,对于IIS7来说,你还可以使用处理器映射配置工具(装的不是中文版IIS翻译不准,英文为Handler Mappings configuration tool),如下图所示。


说明:Windows7/IIS7.5

上图中*.aspx被配置给了aspnet_isapi.dllaspnent_isapi.dll这个非托管的dll在操作系统启动时就已经被IIS加载到了内存中,该dll与托管环境进行交互然后将控制权转交给该应用程序所在的隔离的应用程序域的.NET CLRCLR接到控制权后,接着实例化一个HttpRuntime类对象,然后调用该HttpRuntime实例对象的ProcessRequest方法从而驱动后续的处理,当ProcessRequest执行结束的时候封装请求上下文信息的HttpContext实例就被构建完成了,继续,进入Asp.net运行时管道(可能叫做管线会更好些,MSDN上翻译的是管线),这个管道就像是条工厂中车间的流水线,而这条流水线上加工的对象就是前面HttpRuntime实例化出来的那个封装请求上下文信息的HttpContext实例对象,每个HTTP模块和管道后端的HTTP处理程序都是一道加工工序,这些工序有的负责验证权限,有的负责Asp.net的状态管理等,我把这个过程不确定的归结为职责链模式(C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG路径下<httpModules>节点中注册了这些默认的HTTP模块),接下来就是在管道中按照HTTP模块注册的顺序挨个执行各个HTTP模块,最后到达管道尾端的HTTP处理程序,比如我们的Page类就是一个实现了IHttpHandler接口的处理程序。再往下就是控件以及页面生命周期等这些我们非常熟悉的东西了。值得说明的是,在我们的Global.asax中从System.Web.HttpApplication类继承而来的那个自定义类中按照约定的方式书写代码就是我们与所有这些Http模块们交互的方式了。其实对于System.Web.UI.Page的实例化实际上是通过工厂来返回的,上图注册*.aspx的时候就是注册到了默认的PageHandlerFactory工厂了,该工厂实例再根据前面所有那些步骤中一直存在的最后封装到了HttpContext中的请求的URL对应的文件名来查找相应文件名的的真实的.aspx文件,并读取该文件的第一行指令,指令指定了最终负责处理该请求的HTTP处理程序类,这个类就是我们编写的 System.Web.UI.Page类(一般是从Page继承过来的子类)。接下来服务器控件与组件以及页面的执行最终生成HTML页面内容,生成的HTML结果返回给开始的aspnet_isapi扩展最后被IIS输出。而控件以及页面生命周期等这些已经是我们非常熟悉的领域了。有兴趣的话你可以翻阅MSDN或者觉得有什么意义的话更进一步用Reflector沿着流程从System.Web.UI.PageHandlerFactory开始查看源代码。

说明:Http模块就是实现了IHttpModule接口的类,Http处理程序就是实现了IHttpHandler接口的类。老赵说过:如果你不理解Http模块和Http处理程序的话就不能称为真正熟悉Asp.net,之所以要理解HttpModuleHttpHandler是因为理解了他们之后才能明明白白地基于HttpModuleHttpHandler进行编程,扩展我们的Asp.net应用程序管线中的内容(原话可能不是这样,意思应该是这样)。如果你想了解HttpModuleHttpHandler的话,有两本书非常值得推荐:微软出版社的《Asp.net 3.5技术内幕》和Wrox的《Asp.net 2.0服务器控件与组件高级编程》这两本书的相关章节都有对该主题较好的介绍。阅读小洋(燕洋天工作室)的浅谈ASP.NET内部机制系列或者张子阳的关于Asp.net的文章也是一个不错的选择。Asp.net MVCHttpModuleHttpHandler级别上与原来的Asp.net是完全一样的。

Asp.net是如何被关联的

         在你安装.NET Framework的时候(或者执行aspnet_regiis.exe的时候),安装程序自动注册了*.aspx,*.axd,*.ashx,和其他一些扩展名到一个特殊的名字叫做aspnet_isapi.dllISAPI扩展程序。一个请求必须与一个注册过的扩展名相匹配,然后IIS将激活aspnet_isapi.dll,这个非托管的dll再把控制权转交给托管代码,接下来就是托管代码的时间了,.NET CLR在一个不同的进程中执行这些接下来的非托管代码。

无后缀URL的问题

传统上,该系统对Asp.net服务器页面来说一切正常,因为它们对应真实的以.aspx为后缀文件真实的存在与磁盘上。但是,对于新的路由系统来说就不是这样了,对于routing来说URL不需要与磁盘上的真实文件对应甚至不需要有扩展名。

         这个新的URL路由系统是作为一个.NET HTTP模块创建的。该HTTP模块是被假设为处理所有请求来创建的,该模块是判断和决定对一个请求的控制是否可以转入到你的Asp.net MVC项目的某个控制器并由该控制器来接待。但是这是.NET托管代码,所以只有在请求能够激活ASP.NET的条件下才能够往下进行(比如IIS将请求映射给了aspnet_isapi.dll)。所以除非该请求URL具有合适的扩展名,否则aspnet_isapi.dll根本不会被激活,这意味着IIS将会把该请求作为静态请求尝试返回相应于URL的静态文件的内容,因为磁盘上并没有这个静态文件存在,所以我们将得到一个404 Not Found错误。如何才能做到可以使用无扩展名的URL呢!我们大部分希望将Asp.net MVC项目部署到IIS6上的人开始都会遇到这个问题。接下来的文字中我们会给出四个解决方案以供选择。

 

这部分内容太基础和透明,很难把握,对于存在的不正确的地方希望朋友们指出来,回头改正以免误导。下一篇真正进入Asp.net MVC的部署。
————————————————
添加于2009.9.19

ASP.NET执行循序

首先第一次运行一个应用程序(WebSite或者WebApplication都是Web应用程序)
第一次请求 ->

1,IIS ->

2,aspnet_isapi(非托管dll) ->

3,HttpRuntime(到这里已经是托管的了)HttpRuntime中只有一个方法ProcessRequest 这个方法是整个应用程序的入口点 HttpContext就是在这个方法里面构建的 出了这个方法后HttpContext就构建完成了 ->

4,执行HttpApplication类的Start方法(因为是第一次请求,HttpApplication还没有建立即应用程序池中还没有该站点的HttpApplication对象存在,再第二次请求的时候应用程序池中就已经有HttpApplicationd对象了就不会执行这个方法了 只有应用程序池里没有该站点的HttpApplication对象的时候才会执行这个方法) ->

5,初始化各个HttpModule在HttpModule的Init方法中注册HttpApplication的事件方法 而Init中的HttpApplication就是那个新建立的或者从HttpApplication池中得到的那个->

6,按照顺序执行HttpModule们注册给HttpApplication的事件方法 ->

7,首先是Application的BeginRequest事件方法 这个事件的方法列表中的方法分散在任何地方 在HttpModule里有该事件的方法 所以后续的执行回反复进入HttpModule中去执行这些注册给HttpApplication事件的方法 其中HttpApplicaiton的事件方法在HttpApplication自己里面是按照约定的方法注册的 这里是约定的编程方式必须加上"HttpApplicaiton_"前缀 在HttpApplication_Start后的某个时候使用反射注册这些约定命名的方法到对应的HttpApplication的事件列表方法 ->

8,接着按照HttpApplication中事件的顺序执行注册给HttpApplication余下事件的事件方法 在HttpApplication执行到中间的某个环节的时候开启执行HttpHandler HttpHandler执行完了 Application的最后的事件是EndRequest 执行HttpApplication的EndRequest事件方法列表中的方法 这些方法有的在HttpModule中所以最后又进入HttpModule HttpModule的Init方法是给HttpApplication注册事件方法的唯一地方 最后看注册给HttpApplication的事件方法列表总方法都是分别在哪里 由HttpApplication的事件执行顺序决定整个管道中的流程 HttpModule的Init方法是唯一一个可以访问HttpApplication对象的地方 HttpModule在Init里给这个HttpApplication对象注册事件把HttpModule的自己的方法作为HttpApplication的事件方法横插在HttpApplication的事件流程中

HttpApplication的各个事件执行顺序就是所谓的管道 当一个请求进来的时候 IIS根据请求的Url把请求交给相应的站点 如果该站点是ASP.NET支持的话 HttpRuntime从HttpApplication应用程序池中取出一个HttpApplication对象 然后把这个取出来的HttpApplication对象交给HttpModule的Init(HttpApplication application)方法 HttpModule再给这个HttpApplication的“事件”插入“事件方法” 在HttpApplication中间会通过HttpHandlerFactory根据请求的Url的文件名以及扩展名决定经过哪一个HttpHandler 因为HttpHandler不是每一个都要经过的而是取决于Url的文件名和扩展名所以HttpHandler必不能保有对HttpApplication以及HttpModule这些对于每个请求都会经过的对象 否则的话HttpHandler就可以编程HttpApplication了 而这个HttpApplication会被放回HttpApplication应用程序池 就是网站应用程序池 也就是IIS上建立的那个池 那个池中存的就是该站点的HttpApplication对象
注意:HttpApplication被放入IIS的ASP.NET Web应用程序对象池的事件是在所有的HttpModule的Init方法被执行之后 第二次请求的时候是不会再经过HttpModule了 但是因为有的HttpModule在Init中把自己的方法注册给了HttpApplication的事件 所以后面才会反复进入HttpModule去执行HttpApplication的事件方法 如果HttpModule的Init方法不是把自己的方法注册给HttpApplication而是这个方法在其他地方那就不会再进入HttpModule了 也就是HttpModule里只有一个方法Init这个方法跟HttpApplication的Start方法一样是只会被执行一次的

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
asp.net MVC 应用程序的生命周期(上)
ASP.NET页面与IIS底层交互和工作原理详解
ASP.NET必须知道的:HttpModule,HttpHandler-程序开发-红黑联盟
Asp.Net生命周期系列一
WCF技术剖析之二:再谈IIS与ASP.NET管道
从底层角度看ASP.NET-A low-level Look at the ASP.NET...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服