应用程序域
使用.Net建立的可执行程序*.exe,并没有直接承载到进程当中,而是承载到应用程序域(AppDomain)当中。应用程序域是.Net引入的一个新概念,它比进程所占用的资源要少,可以被看做是一个轻量级的进程。一个应用程序域可以有多个线程,一个线程也可以穿梭于多个应用程序域。
那为什么会出现应用程序域呢?根据它的名字"域"我们可能会联想到域名,其实差不多就是这个概念了,ASP.NET通过这个应用程序域,主要的功能就是进行隔离.
这样在不一个网站死掉的情况下,部署在IIS上的其他网站也不至于死掉.所有所它最重要的功能就是"隔离"
下面来简单看看它的使用
当需要在AppDomain加载可执行程序时,可以使用ExecuteAssembly方法。
如,建一个控制台程序:
class Program { static void Main(string[] args) { Console.WriteLine("供应用程序域执行!"); Console.ReadKey(); } }
将上面程序生成的路径保存到:C:UsersChenZhuoDesktopConsoleApplication1ConsoleApplication1inDebugConsoleApplication1.exe
下面我们创建一个应用程序域并执行上面那个程序集:
public class Program { static void Main(string[] args) { var domain = AppDomain.CreateDomain("MyAppDomain"); //执行指定的程序集 domain.ExecuteAssembly(@"C:UsersChenZhuoDesktopConsoleApplication1ConsoleApplication1inDebugConsoleApplication1.exe"); Console.ReadKey(); } }
输出结果如下:
需要注意的是如果需要卸载的话,只能把整个AppDomain卸载掉
然后我们就来到了网站应用程序的大门
也就是浏览器和ASP.NET的初次交涉,将请求封装成HttpWorkRequest对象,并通过HttpRuntime.ProcessRequest()这个方法传入封装对象来处理请求
然后就得到了一个最最重要的对象HttpApplication 应用程序对象
为什么说这个对象是最重要的呢?因为处理管道就在这个对象里面,由于HTTP连接的特性----------->无状态的短连接,所以我们的每一次请求都会创建一个HttpApplication
对象,为了节省内存的开销,就有了一个HttpApplictionFactory的一个工厂对象来管理HttpApplication对象,同时还会生成一个混合对象HttpContext,
为什么会有这个对象呢?就是为了方便我们进行管理,能用一个东西说明的就不用两个东西来说明!!!!
然后呢,为了响应请求,ASP.NET需要很多很多的事情,于是就有了管道这个概念,
管道:
就是处理复杂问题的时候,将处理的过程分解为多个处理步骤,我们将这种经过多个步骤的处理方式称为处理管道
自定义处理管道:
继承自System.ComponentModel.Component
有一个Events集合管理
简单的例子:
class Handler:Component { private static readonly object startEvent = new object(); private static readonly object stopEvent = new object(); public event EventHandler StartProcess { add { this.Events.AddHandler(startEvent, value); } remove { this.Events.RemoveHandler(startEvent, value); } } public event EventHandler StopProcess { add { this.Events.AddHandler(stopEvent, value); } remove { this.Events.RemoveHandler(stopEvent, value); } } protected void OnStartProcess(EventArgs e) { if (this.Events[startEvent]!=null) { ((EventHandler)this.Events[startEvent])(this, e); } } protected void OnStopProcess(EventArgs e) { if (this.Events[stopEvent] != null) { ((EventHandler)this.Events[stopEvent])(this, e); } } public void Process() { OnStartProcess(EventArgs.Empty); OnStopProcess(EventArgs.Empty); } }
static void Main(string[] args) { Handler h = new Handler(); h.StartProcess += h_StartProcess; h.StopProcess += h_StopProcess; h.Process(); Console.Read(); } static void h_StopProcess(object sender, EventArgs e) { Console.WriteLine("停止处理......"); } static void h_StartProcess(object sender, EventArgs e) { Console.WriteLine("开始处理....."); }
通过这个例子我们就可以看出来,管道可以通过事件暴露出来,也就是说我们可以自定义管道对应的处理方法,也就是过滤器,
在ASP.NET中为了拓展管道的事件分别引入了下面两个类
1.IHttpModule
2.global.asax
但是在这两个中来拓展的方法稍微有点不同,在IHttpModule
//先看定义 public interface IHttpModule { void Dispose(); void Init(HttpApplication context); }
所有所我们应该这样来拓展
public void Init(HttpApplication context) { // 下面是如何处理 LogRequest 事件并为其 // 提供自定义日志记录实现的示例 context.LogRequest += new EventHandler(OnLogRequest); context.BeginRequest += context_BeginRequest; }
并在Web.config中配置这个模块
<httpModules> <add name="模块名称" type="命名空间.模块名称,程序集名称"/> </httpModules>
在 Global中就不是这样配置了,需要满足一定的要求
1.Application_HttpModule中的方法
2.满足System.EventHandler
3.必须为public
然后我们就来到了处理管道,在这个管道中有19个处理事件,在这里就不详细的介绍了,我们只需要知道其中的几个重要的方法就可以了
1.PostMapRequestHandler //找到对应的Handler
那是通过什么样的机制来找到对应的处理程序?比较一个网站不可能只有一个页面,一个请求
我们可以通过配置文件来配置,格式如下:
在system.web配置元素的子元素httpHandlers来配置
add
verb 通过一个逗号(,)分割的Http请求类型列表,例POST,GET,或者*代表全部
path 表示通过一个固定的URL路径或者一个使用星号(*)的通配符来匹配请求的URL,例如*.xu 代表处理所有后缀为xu的网页
type 处理程序的类型,格式为("命名空间.类名","程序集名称");
validate 如果设置为假,者在第一次匹配后,再不使用
removeclear
那么为什么我们的一般处理程序*.ashx没有配置呢?是因为系统已经帮助我们定义了
定义内容如下:
<add verb="*" path="*.ashx" type="System.web.UI.SimpleHandlerFactory" validate=true />
从上面这个配置节就可以看出来,拓展名为ashx的处理程序是被SimpleHandlerFactory进行管理的
SimpleHandlerFactory找到对应的ashx文件
通过反射得到类的实例
通过GetHandler返回实例给HttpApplication
2.PostRequestHandlerExecute //执行Handler
3.EndRequest //结束请求
当然一般情况下我们请求的都是一个后缀为*.aspx的不同页面,它也是一个处理程序,定义如下
<add verb="*" path="*.aspx" type="System.web.UI.PageHandlerFactory" validate=true />
那么页面是怎么生成的呢?我们知道一个HTML页面除了字符串还是字符串,那是不是我们生成的页面也都是字符串?
那是当然了,这一切都是字符串.为了方便使用ASP.NET把对应的标签生成了一个一个对应的对象,这样即方便管理又可以重复使用.
所有的控件都继承至Control包括Page
下面我们来看一下他们的继承关系
>Control
>TemplateControl
>Page
>UserControl
>WebControl
>HtmlControl
>CompositeControl
>Panel
>Part
>WebPart
从这个关系中我们就可以看出来Page和UserControl是基于模板产生的,但是想想也不觉得奇怪,毕竟一个Page承担了好多的东西
然后控件又分为了服务器控件和Html控件,这个其中Html控件是静态的,服务端控件是动态的,当然在动态控件中的内容也是Literal对象
既然有了模板,又有了控件,我们基本上就可以做出一个简单的网页了,可是这样并不能保存状态,于是为了保存状态,ASP.NET使用ViewState
来保存对应对象的状态,具体的做法就是将对象序列化为二进制对象,但是网页不能有二进制对象,于是就把他转换成了Base64格式的字符串.
然后放在网页中的隐藏域来进行保存,这样在我们回发请求的时候就会顺带的把这个隐藏域中的内容发送到服务端.然后回复上一次的状态.
具体的做法如下:
在页面的事件处理管道InitComplete 和PreLoad 之间做状态的恢复,然后再onLoad事件以后触发对象引发的事件
然而加载和保存需要实现一个接口---->IStateManager
public interface IStateManager { //表示控件是否使用视图状态 bool IsTrackingViewState{get;} //管理视图状态的方法 void LoadViewState(Object state);//从视图状态取回数据 Object SaveViewState();//保存视图状态 void TrackViewState();//开始使用视图状态 }