.NET 计划

帮助你学习.NET,我们的目的是要精通.NET!

导航

.NET计划之ASP.NET的基础构架!

Posted on 2004-12-09 09:08  FREE一族  阅读(1888)  评论(3编辑  收藏  举报
昨天我们学习了ASP.NET运行环境的配置,今天我们来看一看ASP.NET的基础构架。

.NET计划之ASP.NET的基础构架


写在前面的话:今天的计划包含有很关于面象对象程序设计的内容,请大家先参考相关资,对这些概念了解一下,如类、事件、方法、属性、继承、接口等概念,推荐下载C#入门经典


1、ASP.NET的核心:

      ASP.NET的核心是许多的.NET类,它们之间相互密切合作,对HTTP请求提供服务。这些类一部份在系统程序集中定义,作为基础类库的一部份,并在.NET运行时装入;一部份被载入全局程序集缓存(Global Assembly Cache,GAC);还有一部份从与应用程序相关联的虚拟目录中的本地程序集中载入;所有这些类都被载入ASP.NET工作者进程内的应用程序域中,而且它们相互作用对给定的请求作出响应。

 

在ASP.NET中构建应用程序的过程就是构造与基础框架中的类交互的类的过程,在用户编写的类中,有一些派生于基础框架中的基类,一些可能会实现一些接口,而其它的类则只是简单的调用框架中的方法来实现它们的交互.ASP.NET文件服务器端的代码被转化为类定义,并在第一次访问时被装入程序集中。

2、ASP.NET的进程模型

     在IIS 5.0中,ASP.NET工作者进程(Work Process)是从Inetinfo.exe(internet信息服务器(IIS)进程中分离出来的一个单独的工作者进程——aspnet_wp.exe,在IIS 6.0中,asp.net驻留在一个称为w3wp.exe进程中,ASP.NET中的进程模型与IIS有关的进程隔离设置无关。 尽管IIS仍然是访问ASP.NET应用程序的典型入口点,在物理上侦听相应的端口,分发请求,但它的作用有所减弱,并且它所处理的许多任务都可以由ASP.NET在它自己的工作者进程中完成。

3、ASP.NET的运行方式

      第一次访问ASP.NET网页时,你会发现,ASP.NET装载页面所需的时间特别长。这是因为在第一次访问页面所需的开销包括:加载ASP.NET工作者进程,对.aspx文件进行语法分析,并把它编译成一个程序集。这与ASP的区别是:ASP总是将服务器端代码交给一个解释进行处理。这样做的好处是:由于ASP.NET网页始终被编译成类,并保存在程序集中,而.NET类中既包括服务器端代码,也包括HTML语句,因此,只要第一次访问了某个ASP.NET网页(或者访问了指定目录中的任何一个网页),以后生成该网页时只需执行已编译的代码即可,大大提高了执行效率。而且,由于网页被编译成类,因此可以使用VS.NET等强大的开发工具进行调试 。
      做为一个初学ASP.NET的开发者,在创作ASP.NET网页的时候,始终应该把它看做是一个类。
 
4、 System.Web.UI.Page

       System.Web.UI.Page类定义了大多数用处请理请求的功能,在默认情况下,每个.aspx网页从Page基类派生而来,也就是说,Page类是.aspx网页的基类,因此理解Page类的功能与特性是非常重要的。
这里以.netFrameWork1.1为例,在.netFrameWork1.1下面,Page类的定义如下:

public class Page : TemplateControl, IHttpHandler
{
// Methods
static Page();
public Page();
[EditorBrowsable(EditorBrowsableState.Never)]
protected IAsyncResult AspCompatBeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
[EditorBrowsable(EditorBrowsableState.Never)]
protected void AspCompatEndProcessRequest(IAsyncResult result);
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual HtmlTextWriter CreateHtmlTextWriter(TextWriter tw);
internal static HtmlTextWriter CreateHtmlTextWriterFromType(TextWriter tw, Type writerType);
internal static HtmlTextWriter CreateHtmlTextWriterInternal(TextWriter tw, HttpRequest request);
private void CreateLosFormatter();
[EditorBrowsable(EditorBrowsableState.Never)]
public void DesignerInitialize();
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual NameValueCollection DeterminePostBackMode();
internal string GetClientScriptFileIncludeScript(string language, string fileName);
internal NameValueCollection GetCollectionBasedOnMethod();
private string GetMacKeyModifier();
[EditorBrowsable(EditorBrowsableState.Advanced)]
public string GetPostBackClientEvent(Control control, string argument);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public string GetPostBackClientHyperlink(Control control, string argument);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public string GetPostBackEventReference(Control control);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public string GetPostBackEventReference(Control control, string argument);
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual int GetTypeHashCode();
internal override string GetUniqueIDPrefix();
private bool HandleError(Exception e);
[EditorBrowsable(EditorBrowsableState.Never)]
protected virtual void InitOutputCache(int duration, string varyByHeader, string varyByCustom, OutputCacheLocation location, string varyByParam);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool IsClientScriptBlockRegistered(string key);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool IsStartupScriptRegistered(string key);
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual object LoadPageStateFromPersistenceMedium();
internal void LoadPageViewState();
public string MapPath(string virtualPath);
internal void OnFormPostRender(HtmlTextWriter writer, string formUniqueID);
internal void OnFormRender(HtmlTextWriter writer, string formUniqueID);
private void ProcessPostData(NameValueCollection postData, bool fBeforeLoad);
private void ProcessRequest();
[EditorBrowsable(EditorBrowsableState.Never)]
public void ProcessRequest(HttpContext context);
private void ProcessRequestCleanup();
private void ProcessRequestEndTrace();
private void ProcessRequestMain();
private void ProcessRequestTransacted();
internal void RaiseChangedEvents();
private void RaisePostBackEvent(NameValueCollection postData);
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterArrayDeclaration(string arrayName, string arrayValue);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterClientScriptBlock(string key, string script);
internal void RegisterClientScriptFileInternal(string key, string language, string fileName);
internal void RegisterClientScriptFileInternal(string key, string language, string location, string fileName);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterHiddenField(string hiddenFieldName, string hiddenFieldInitialValue);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterOnSubmitStatement(string key, string script);
internal void RegisterPostBackScript();
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterRequiresPostBack(Control control);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterRequiresRaiseEvent(IPostBackEventHandler control);
private void RegisterScriptBlock(string key, string script, ref IDictionary scriptBlocks);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterStartupScript(string key, string script);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterViewStateHandler();
private void RenderHiddenFields(HtmlTextWriter writer);
private void RenderPostBackScript(HtmlTextWriter writer, string formUniqueID);
private void RenderScriptBlock(HtmlTextWriter writer, IDictionary scriptBlocks);
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void SavePageStateToPersistenceMedium(object viewState);
internal void SavePageViewState();
internal void SetForm(HtmlForm form);
private void SetIntrinsics(HttpContext context);
public virtual void Validate();
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void VerifyRenderingInServerForm(Control control);

// Properties
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
public HttpApplicationState Application { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected bool AspCompatMode { set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected bool Buffer { set; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
public Cache Cache { get; }
internal string ClientOnSubmitEvent { get; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(""), Browsable(false), WebSysDescription("Page_ClientTarget")]
public string ClientTarget { get; set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected int CodePage { set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected string ContentType { set; }
protected override HttpContext Context { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected string Culture { set; }
[Browsable(false)]
public override bool EnableViewState { get; set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected bool EnableViewStateMac { get; set; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), DefaultValue(""), WebSysDescription("Page_ErrorPage")]
public string ErrorPage { get; set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected ArrayList FileDependencies { set; }
internal HtmlForm Form { get; }
[Browsable(false)]
public override string ID { get; set; }
internal bool IsInAspCompatMode { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool IsPostBack { get; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public bool IsReusable { get; }
internal bool IsTransacted { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool IsValid { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected int LCID { set; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public HttpRequest Request { get; }
internal NameValueCollection RequestValueCollection { get; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
public HttpResponse Response { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected string ResponseEncoding { set; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public HttpServerUtility Server { get; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
public virtual HttpSessionState Session { get; }
[Browsable(false)]
public bool SmartNavigation { get; set; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
public TraceContext Trace { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected bool TraceEnabled { set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected TraceMode TraceModeValue { set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected int TransactionMode { set; }
[EditorBrowsable(EditorBrowsableState.Never)]
protected string UICulture { set; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IPrincipal User { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ValidatorCollection Validators { get; }
[Browsable(false)]
public string ViewStateUserKey { get; set; }
[Browsable(false)]
public override bool Visible { get; set; }

// Fields
internal HttpApplicationState _application;
private bool _aspCompatMode;
private AspCompatApplicationStep _aspCompatStep;
internal Cache _cache;
private ArrayList _changedPostDataConsumers;
private string _clientTarget;
internal HttpContext _context;
private ArrayList _controlsRequiringPostBack;
private bool _enableViewStateMac;
internal string _errorPage;
private bool _fOnFormRenderCalled;
private HtmlForm _form;
private LosFormatter _formatter;
private bool _fPageLayoutChanged;
private bool _fPostBackScriptRendered;
private bool _fRequirePostBackScript;
private bool _inOnFormRender;
private NameValueCollection _leftoverPostData;
private bool _needToPersistViewState;
private IDictionary _registeredArrayDeclares;
private IDictionary _registeredClientScriptBlocks;
private IDictionary _registeredClientStartupScripts;
private ArrayList _registeredControlsThatRequirePostBack;
private IPostBackEventHandler _registeredControlThatRequireRaiseEvent;
private IDictionary _registeredHiddenFields;
private IDictionary _registeredOnSubmitStatements;
internal HttpRequest _request;
private NameValueCollection _requestValueCollection;
internal HttpResponse _response;
private HttpSessionState _session;
private bool _sessionRetrieved;
private SmartNavigationSupport _smartNavSupport;
private int _transactionMode;
private bool _validated;
private ValidatorCollection _validators;
private object _viewStateToPersist;
private string _viewStateUserKey;
private const string clientScriptEnd = "// -->\r\n</script>";
private const string clientScriptStart = "<script language=\"javascript\">\r\n<!--";
private const string IncludeScriptFormat = "\r\n<script language=\"{0}\" src=\"{1}{2}\"></script>";
private const string jscriptPrefix = "javascript:";
private const string postBackFunctionName = "__doPostBack";
[EditorBrowsable(EditorBrowsableState.Never)]
protected const string postEventArgumentID = "__EVENTARGUMENT";
[EditorBrowsable(EditorBrowsableState.Never)]
protected const string postEventSourceID = "__EVENTTARGET";
private static IDictionary s_systemPostFields;
private static char[] s_varySeparator;
private const string systemPostFieldPrefix = "__";
internal const string viewStateID = "__VIEWSTATE";
}

其中很重要的成员有:
public HttpApplicationState Application {get;}
public virtual HttpSessionState Session {get;}
public Cache Cache {get;}
public HttpRequest Request {get;}
public HttpResponse Respone {get;}
public HttpServerUtility Server {get;}
public string MapPath(string virtualPath);
public ClientTarget ClientTarget (get;set;)
public IPrincipal User {get;}
public UserControl LoadControl(string virtualPath);
public virtual ControlCollection Controls {get;}
public override string ID {get;set;}
public bool IsPostBack {get;}
public void RenderControl(HtmlTextWriter writer)
等等.这些成员将在我们以后的计划中详细的讨论它们。下面我们先来看一个例子:
在记事本中写下如下代码:
<%@ Page Language="C#" %>
<script runat="server">
public void MM_Click(Object Src,EventArgs e)
{
string YourIP=Request.ServerVariables["REMOTE_ADDR"];
string Message="我现在的IP是:"+YourIP; 
Response.Write(Message);
}
</script>
<html>
<head>
<title>查看IP</title>
</head>
<body>
<form runat="server">
<asp:Button id="ViewIP" runat="server" text="查看IP" onclick="MM_Click"></asp:Button>
</form>
</body>
</html>
在你的硬盘中新建一个文件夹,把它命名为DotNet计划,把记事本中的代码另存为041209_01.aspx,然后在IIS中新建一个虚拟目录,命名为dotnetplan并指向DotNet计划文件夹,在IE地址栏中打入如下地址:http://localhost/dotnetplan/041209_01.aspx,你就会看到下图所示的网页。
 
单击查看IP会看到如下的网页:

如果你还没有接触过ASP.NET,那先让我来帮你介绍一下以上代码的意思。首先,你会注意到,在script块和asp:Button标记中,都加上了runat="server"这个属性,这表示这段代码是运行于服务器的,从我们前面的介绍中我们可以猜到, public void MM_Click(Object Src,EventArgs e) 将成为 041209_01.aspx所生成类的一个方法,而 <asp:Button id="ViewIP" runat="server" text="查看IP" onclick="MM_Click"></asp:Button>将成为 041209_01.aspx中一个类的实例,实例的名称是ViewIP。 关于服务端代码和WEB控件将会在以后的计划中详细的介绍.

5、代码隐藏

      为了防止静态的布局元素与服务器端脚步本混全在一起而引发纠缠不清、难以理解等后果,ASP.NET增加了一种代码隐藏技术来将编程逻辑与网页的静态布局隔离开来.
      代码隐藏是一种创建中间基类(介于Page基类和机器根据.aspx文件所生成的类之间)的技术,中间基类直接从Page类派生而来,而根据.aspx所生成的类直接派生于中间基类,而不是派生于Page类,使用这种方法,可以向代码隐藏类中添加字段方法和事件处理函数,并可以让那些根据.aspx文件所创建类继承这些特性,从而可以从.aspx文件中移出大理的代码,这种技术依赖于自动生成的类指定另一个基类的能力,可以同Page指令的Inherits属性来指定。
下面我来将上面的例子改写成使用代码隐藏的技术的形式:
首先在记事本中写下如下的代码:
<%@ Page Language="c#" Inherits="DotNetPlan.ViewYourIP" %>
<html>
<head>
<title>查看IP</title>
</head>
<body>
<form runat="server">
<asp:Button id="ViewIP" runat="server" Text="查看IP"></asp:Button>
</form>
</body>
另存为041209_02.aspx,接着在记事本写下如下代码:
using System;
using System.Web;
using System.Web.UI;
namespace DotNetPlan
{
public class ViewYourIP : Page
{
protected System.Web.UI.WebControls.Button ViewIP;
protected override void OnInit(EventArgs e)
{
this.ViewIP.Click += new System.EventHandler(this.ViewIP_Click);
}
private void ViewIP_Click(Object Src,EventArgs e)
{
string YourIP=Request.ServerVariables["REMOTE_ADDR"];
string Message="我现在的IP是:"+YourIP;
Response.Write(Message);
}
}
}
另存为041209_02.aspx.cs,值得说明的是,代码隐类必须编译成一个程序集,并部署到应用程序的/bin目录下。下面我们来开始执行编译,进入cmd命令提示符下面,转到dotnetPlan目录(例如:E:\site\dotnetplan),打入如下命令:csc /t:library /out:bin\041209_02.dll 041209_02.aspx.cs 现在就反隐藏代码编译成了dll文件,下面我们来打开这个网页, 在IE浏览器地址栏中打入:http://localhost/dotnet/041209_02.aspx ,看到以下效果


点击查看IP后,


还可以使用Page指令的SRC属性来指定隐藏代码。这样做的好处是:只要通过替换文件就可以理新代码隐藏程序集文件,并在下一个请求到来时,重新编译所引用的文件,而不必自己动手编译

6、事件处理

      事实上,在上面的例子中,我们以前接触过了事件处理,如Page的OnInit事件,Button的Click事件,在代码隐藏类中定义事件,这种特性使用我们不必在.aspx文件中定义额外的代码,就可以控制网页的生成,从而产生一个"干净"的网页,Page基类定义了4个事件(实际上,它们都是从Control基类继承而来的);Init,Load,PreRender和Unload,在网页的生命历程中,依次调用它们。
Init事件发生在任何服务端状态还原完成之前;Load事件发生在服务端状态还原完成之后,便在激发所有的事件之前;PreRender事件发生激发所有服务端事件之后,但在生成HTML代码之前。Unload事件发生在网页生成完成之后。在这四个事件里面,我们用得最多的就是Load事件了,呵呵!!
      可以通过重写OnInit虚方法( protected override void OnInit(EventArgs e) ),以手工方式为Page类的Load事件订阅一个委托( this.Load += new EventHandler(MyLoadHandler) )。
也可以通过AutoEventWireup技术,使用这个技术时,只需要在派生类中(命名为Page_Init,Page_Load,Page_PreRender或Page_Unload)添加一个方法,以及EventHandler委托所需的签名。创建Page派生类时,在初始化过程中可以用反射技术查找与这些名字匹配的函数,如果找到这样的函数,则初始化例程创建一个新的委托,并用该函数初始化它们,然后订阅相关的事件。这种技术有一种缺点,它需要依靠运行时类型信息查找方法的名称和订阅事件,从而导致效率低下。如果不用这种技术订阅事件,可以通过把Page指令的AutoEventWireup属性设为false,禁止运行时查找类型。vs.net中,默认都将Page指令的AutoEventWireup属性设为false。

7、影子复制和动态程序生成

     在上面的例子中,我们通过将041209_02.aspx.cs 编译成布署在/bin目录下的程序集,来实现了代码的隐藏.在传统的ASP应用程序中,按这种方式部署所用的组件时,会使得更新与替换极其困难,只要应用程序正在加载或者运行,都要保留一个到组件文件的引用,因此替换该组件,就不得不关闭IIS。
     在ASP.NET中,通过使用CLR(公共语言运行时)提供的影子复制(shadow copy)机制,可以实现:正在引用的文件没有保持对一个组件文件的引用,并且无论何时用新版本的组件文件替换原来的组件文件,该版本组件必须承接所有以后对应用程序发出的请求。
     在.NET中创建一个新的应用程序域时,可以将程序集的影子副本进行配置。AppDomainSetup类(该类用于初始化AppDomain)向外界提供一个Bollean类型的ShadowCopyFiles属性和一个string类型的CachePath属性;AppDomain类向外界提供一个SetShadowCopyPath()方法,用于启用特定应用程序域的影子复制功能,Boolean型的ShadowCopyPath属性为特定应用程序域启用该机制,CachePath用于指定影子副本的基目录,SetShadowCopyPath()指定哪个目录可以启用影子复制。
ASP.NET为工作者进程中的每一个应用程序创建一个单独的应用程序域, 对于每个这样的域。 启用/bin目录下的所有被引用的程序集的影子复制。 程序集加载集不是直接从/bin目录下加载程序集,而是将所引用的程序集以物理方式复制到一个单独的目录(必须在应用程序的配置设置中指定该目录)。然后从那儿加载,这种机制还跟踪程序集的出处,因此,如果将程序集的新版本放在/bin目录之下,则会把它重新复制到影子目录中,以后引用该目录。
     除了影子复制外,ASP.NET还必须能够临时创建和加载程序集,我们已经知道,在第一次引用.aspx文件时,先把它编译成程序集,然后被asp.net加载,然后编译完成之后,我们不知道程序集放在什么地方。应用程序域还支持动态目录概念,这是一个为了存放动态创建的程序集而设计的目录,于是程序集加载集就可以引用其中的程序集。ASP.NET将每个应用程序的运态目录设定为Temporary Asp.NET Files 目录下的一个子目录,而且取名为应用程序的虚拟目录名。
    动态程序生成和影子复制的一个结果是,许多程序集都是在ASP.NET的应用程序生命周期内复制的。对于不在引用的程序集,应该及时清除。在目前发布的asp.net版本中,能够自动的清除程序集。