ASP.NET

ASP.NET的事件模型

ASP.NET 的原始设计构想，就是要让开发人员能够像VB 开发工具那样，可以使用事件驱动式程序开发模式(Event-Driven Programming Model) 的方法来开发网页与应用程序，若要以ASP技术来做到这件事的话，就必须要使用大量的辅助信息，像是查询字符串或是窗体字段数据来识别与判断对象的来源、事件流向以及调用的函数等等，需要撰写的代码量相当的多，但 ASP.NET 很巧妙利用窗体字段和JavaScript脚本把事件的传递模型隐藏起来了。
ASP.NET 的事件模型是由<form runat="server"></form> 以及数个Hidden Field 组合而成，基于 HTTP 模型的限制，所有的网页程序在运行结果输出到客户端后，程序就会结束运行，为了维护在ASP.NET 网页与控件的状态数据，因此在输出ASP.NET 控件时，ASP.NET 会将部分状态数据存储到网页的Hidden Field 中，这类型的状态数据称为ViewState（ID 为 __VIEWSTATE），在服务端即会被解译出状态与事件数据。在大多数的内置Web 控件中都有使用到这个机制，因此在使用大量ASP.NET Web 控件的网页中，会有许多的ViewState 会存放在网页中并随着HTTP 数据流输出到客户端，ViewState 在输出时，会被加密为一组乱码字符串，其密钥值定义在计算机中，并且每一个对象都会被序列化(serialize) 成字符串（因此若是自定义对象要放到ViewState 时，则应要让它支持序列化），再输出到__VIEWSTATE 字段中，在每次的网页来回时都会被传输，较大的ViewState 会让网页大小膨胀，不利于快速的网络传输，不过 ASP.NET 本身有提供将ViewState 关闭的功能，因此如果控件不需要状态保存时，可将它关闭以减少输出的大小。
为确保控件的事件能够确实被引发，让事件驱动能够被运行，因此控件事件引发命令时需要的参数，是交由JavaScript 脚本在客户端引发时，填入另一个Hidden Field（ID 为 __EVENTTARGET 以及 __EVENTARGUMENT），并且引发窗体的提交指示(submit)，发送到伺服端后，伺服端的HttpApplication 中的工具函数会解析__EVENTTARGET 和 __EVENTARGUMENT 字段中的信息，并且交由控件所实现的RaisePostBackEvent() 来引发事件，并由.NET Framework 内部的事件处理机制接手处理（调用控件设置的事件处理函数）。

绘制技术

熟悉 ASP 技术的人都知道，代码都是混在HTML 标签之间，以输出预期需要的HTML 指令，这个技术在ASP.NET 中，由各控件的绘制 (Render) 机制包装起来了，绘制机制装载了HtmlTextWriter 对象，由它来产生HTML 指令，它会输出至HttpContext 的 Response 输出数据流中（即 ASP 技术的Response.Write()），下列代码为绘制技术的示例：
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")] 
protected override void Render(HtmlTextWriter output) 
{
    if ( (HasControls()) && (Controls[0] is LiteralControl) ) 
    {
        output.Write("<H2>Your Message: " + ((LiteralControl) Controls[0]).Text + "</H2>");
    }}
为了让控件的输出有层次结构性，ASP.NET 开发了一个可以层次结构化输出控件HTML 指令的方式，称为控件树(Control Tree)，借由控件树，可以让各个控件的输出可以层次结构化，不论是否是收纳型控件，还是一般型的控件，都可以按照控件的顺序来输出。

应用程序层级对象

Application 对象会在应用程序的Application_OnStart 事件中初始化，并使用名称来识别数据（它是一个NameObjectCollectionBase 集合的实现品），它会存储在应用程序的范围内，所有的连线（用户）都可以使用，属于共享型的存储体，适合存储所有用户都可使用的数据，在多人使用的情况下，可以适当的使用Lock/Unlock 的机制来确保应用程序状态的更新。
Application.Lock();Application["PageRequestCount"] = 
    ((int)Application["PageRequestCount"])+1;Application.UnLock();

连线层级对象

连线层级的对象是Session，以浏览器的运行个体为识别单位，数据依浏览器的运行个体来存储，在浏览器的运行个体第一次连到应用程序时，ASP.NET会设置一个Session ID，并且使用它来识别Session，每一个Session 都是ICollection 与 IEnumerate 的实现，用 key 来识别数据值，并且具有时间的限制(timeout)，若超出时限时服务器会自动清理掉，默认的Session 时限为20 分钟。Session ID 的算法是由RNGCryptoServiceProvider（密码编译随机数产生器提供者）产生，并编码成一个Session ID 字符串（例如 anf4vuup3xiq0arjlqla2l55 这样的字符串）存储在服务器中，用以识别不同的Session 个体。
为因应不同的客户端，ASP.NET 设计了不同的Session ID 存放机制，像是旧式的浏览器或是移动客户端这种不支持本地存储cookie的设备时，ASP.NET 可以直接在URL 中加上Session ID 的识别，像是http://www.example.org/(anf4vuup3xiq0arjlqla2l55)/profile.aspx 这样的URL，可以由开发人员自行设置，或是使用AutoDetect 设置来让ASP.NET 自行判断要使用的Session ID 存放方式。
Session ID 的产生方法可以由程序开发人员自定义，借由改写SessionIDManager 的 CreateSessionID() 方法来自定义。
using System;using System.Configuration;using System.Web.Configuration;using System.Web;using System.Web.SessionState;namespace Samples.AspNet.Session{

  public class GuidSessionIDManager : SessionIDManager
  {

    public override string CreateSessionID(HttpContext context)
    {
      return Guid.NewGuid().ToString();
    }


    public override bool Validate(string id)
    {
      try
      {
        Guid testGuid = new Guid(id);

        if (id == testGuid.ToString())
          return true;
      }
      catch
      {
      }

      return false;
    }
  }}

部件

ASP.NET 是开发Web 应用程序的基础架构(framework)，除了它内部的运作方法外，对外也显露了许多的开发支持，让开发人员可以利用它来发展出许多强大的Web 应用程序解决方案。

网页

ASP.NET 最基础的底层为网页(Page)，网页由System.Web.UI.Page 类别来提供基础支持，包含了页面的事件以及对象绘制的引发点（Page 类别本身是一个HTTP Handler 的实现品）。ASP.NET 网页在微软的官方名称中，称为Web Form，除了是要和Windows Forms作分别以外，同时也明白的刻划出了它的主要功能：“让开发人员能够像开发Windows Forms 一样的方法来发展Web 网页”。因此 ASP.NET Page 所要提供的功能就需要类似Windows Forms 的窗体，每个Web Form 都要有一个<form runat="server"></form> 区块，所有的ASP.NET 服务器控件都要放在这个区域中，这样才可以让ViewState 等服务器控制能够顺畅的运作。
在网页中也可以使用代码，以类似于ASP时代的撰写方式来开发，此种开发方式称为inline code，在 ASP.NET 的程序开发模式中，inline code ，要放在<script runat="server"></script> 区域中，如下列的示例程序：
<%@ Page Language="C#" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
 
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongDateString();
    }
 
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">
    <title>Sample page</title></head><body>
    <form id="form1" runat="server">
    <div>
        The current time is: <asp:Label runat="server" id="Label1" />
    </div>
    </form>
 
</body></html>
另一种模式则是将代码和网页分离，这种模式称为代码后置(Code-Behind)，这个方法可以将代码独立到一个文件中，网页可以保持较干净的状态，让维护网页程序的复杂度降低很多，在网页的提示指令(directive) 中，可以设置代码后置的参数，像是Inherit、CodeFile、Class 等参数。
<%@ Page Language="C#" CodeFile="SampleCodeBehind.aspx.cs" Inherits="Website.SampleCodeBehind" 
AutoEventWireup="true" %>
而一个典型的代码后置例子为：
using System;
 
namespace Website{
public partial class SampleCodeBehind : System.Web.UI.Page
{
protected override void Page_Load(EventArgs e)
{
base.OnLoad(e);
}
}}
使用代码后置模式的设置时，可以让ASP.NET 运行引擎在加载网页时，由代码后置参数获取对应的类别信息，藉以使用Reflection 的方式来运行后置的代码。
ASP.NET 可以支持HTML和XHTML两种网页内容，但在Visual Studio.NET中，默认是使用HTML，但在Visual Studio 2005以后的版本，则一律都改用XHTML格式。

应用程序服务

应用程序服务(application services) 是在ASP.NET 2.0 中才开始提供，它以Provider-based Pattern 为主，实现出数个网站的常用服务，包含会员服务(Membership Service)、角色服务(role service)与配置文件服务(profile service) 等。
会员服务由Membership 以及其数据提供者MembershipProvider 构成，应用程序使用Membership 所显露的方法来操作，它会将要求转送给指定的MembershipProvider 实现来处理，ASP.NET 当前支持来自于数据库的SqlMembershipProvider（支持 SQL Server）以及来自于活动目录的 ActiveDirectoryMembershipProvider，开发人员也可以自行由MembershipProvider 继承来实现自定义的会员服务数据提供者。
角色服务与会员服务类似，由 Role 以及其数据提供者RoleProvider 构成，应用程序使用Role 所显露的方法操作，由 RoleProvider 实现提供数据服务，当前内置的RoleProvider 有来自 活动目录 或XML 文件的AuthorizationStoreRoleProvider，由 SQL Server 供应数据的SqlRoleProvider，以及支持Windows 角色的WindowsTokenRoleProvider 三种，开发人员可自行实现RoleProvider 的方法以发展出自定义的角色服务提供者。
配置文件服务是一个特殊的服务，它结合了.NET Framework 的 CodeDOM 开发模式，以及 System.Web.Profile 名字空间的ProfileBase、ProfileInfo 与 ProfileManager 等类别，组合出完整的配置文件支持，其数据源也是以Provider-based Pattern 为主，由 ProfileProvider 提供，ASP.NET 内置由SQL Server 数据库创建的SqlProfileProvider，其字段系由开发人员在ASP.NET 配置文件中自行定义，再由ASP.NET 动态产生强类型的字段属性。
配置文件服务也是作为ASP.NET 2.0 的网页组件(Web Part Framework) 所需要的配置文件存储支持，Web Part Framework 可以让开发人员可以开发出具备个性化能力(Personalization) 的网页配置方案，让用户可以用自行新增与拖放的方式来设计自己的网页布置，所需要的设置存储即由配置文件服务处理。
另一个需要和应用程序服务配合使用的功能为Web 事件架构(Web Event Framework)，它需要由应用程序服务提供数据结构，它也有Provider-based Pattern，并可以支持数种的事件数据提供者。

延展性支持

除了 ASP.NET 网页以外，.NET Framework 还提供了两种可以由开发人员自行发展处理模型的模块，一种是HTTP Handler，另一种则是HTTP Module。
HTTP Handler（扩展名为.ashx）由 System.Web.IHttpHandler 接口定义了必要的方法（可支持异步的HTTP Handler 称为HTTP Async Handler，由 System.Web.IHttpAsyncHandler 接口定义），其中最重要的方法是ProcessRequest() 方法，开发人员必须要实现这个方法，才能够让HTTP Handler 有作用，它也可以透过ASP.NET 的配置设置，让 HTTP Handler 可以处理特定的扩展名，它可以被视为.NET Framework 中的ISAPI Extensions 实现方法。
HTTP Module 则是由System.Web.IHttpModule 接口定义，它可以在整个网页生命周期中被调用多次，并实际处理由HttpApplication 所引发的事件，开发人员需要实现IHttpModule.Init() 方法，以及处理HttpApplication 事件需要的代码。它可被视为.NET Framework 中的ISAPI Filter 实现方法。

一致性与多样性接口的支持

ASP.NET 在一开始的时候是缺乏模板引擎 (template engine) 的，其主因是.NET Framework本身是面向对象，且需要用继承的方式才能够延伸功能，大多数的开发人员都是由System.Web.UI.Page 继承并定义出新的基类，并撰写要绘制HTML 的方法，以及在他们的应用程序中修改以继承该类别，然而这个方法可能会被用在网站的很多地方，因而会大大的提升混合代码与标记的复杂度，这个方法也只能在运行期才能够以可视化的方式测试，无法在设计时期可视化，其他的开发人员总是使用原有的ASP 方法（即<!-- #include --> 指令）来把每个网页需要的部分包到网页中，防止在每个网页中都要撰写相同的导览代码。
在 ASP.NET 2.0 中，推出了母板页面(master page)的概念，它可以让开发人员先行定义外观版型(*.master)，再使用它来应用实际运行的网页，网页与主版页面之间以ContentPlaceHolder 的 ID 做链接，以应用正确的内容到保留区（即由ContentPlaceHolder 包住的区域）中，开发人员也可以定义在保留区没有应用时需要显示的默认内容。在 ASP.NET 3.5 中更进一步的支持设计时期的嵌套主版页面(nested master pages)，以及把网页的HEAD 区块纳入ContentPlaceHolder 的范围。
与主版页面相关的，还有主题(Theme)以及面板(skin)技术，这两个技术允许开发人员或设计人员自行定义网页的样式设置以及应用的样式支持，每个主题中可以包含数个面板档，这些面板档决定了控件要输出时应用的样式，开发人员则可以利用主题来决定不同的外观要使用的样式。
ASP.NET 也允许在应用程序中动态的变更主版页面与主题，但必须要在页面的PreInit 事件例程设置。
void Page_PreInit(Object sender, EventArgs e){
    Page.MasterPageFile = "~/NewMaster.master";
    Page.Theme = "MyTheme";}

编译模型

ASP.NET 在 1.x 时，使用的是组件为主的编译方式，一个网页只会产生一个组件，这个方式最大的优点，就是可以自由定义名字空间，且在部署应用程序时会比较方便，但由于ASP.NET 1.x 所处的时代，如果网站是有许多代码的情况下（即 DLL 档很大），加载的速度会变慢，且占用存储器的量会很多，当时的存储器价格也尚未降到现在的水准。因此在ASP.NET 2.0 开始，另外提供了一个预先编译(Pre-compilation) 的编译模型，这个编译方法会将每个网页都各自编译成一个组件，其文件名称会是App_[随机数字符串].dll 命名，在编译时期由ASP.NET Pre-compilation 工具（aspnet_compiler.exe）给定，优点是可以不必加载过量的代码到存储器中，但缺点则是无法自定义名字空间，而且在更新时必须要更新所有的DLL 档以及网页等，否则会造成名称不一致，让 DLL 无法被加载的问题。
早期 ASP.NET 2.0 仅提供预先编译模式，让它的缺点很快的被暴露出来，因此微软也为ASP.NET 2.0 开发了沿用ASP.NET 1.x 的编译模型的工具：Web Application Project，在 Visual Studio 2008 中开始内置，至此，ASP.NET 支持两种编译模式的架构抵定。

安全性支持

ASP.NET 的安全性支持分为验证 (Authentication)与授权 (Authorization)两个部分。

Web Service支持

ASP.NET 1.0 开始支持Web Service 的开发，是微软在原生平台上支持Web Service 发展的第一个实现品，但它却不是微软的第一个Web Service 开发工具实现品，.NET Framework 中提供了一个WSDL.exe，可以连接Web Service 下载WSDL定义档，并产生一个Proxy Class 的源代码，供客户端应用程序使用，若是使用Visual Studio 开发的话，这个动作会由“加入 Web 参考”的动作在背后处理掉。
ASP.NET Web Service 的发展只是平台的基础，微软在Web Service 的开发上提供持续的支持，尤其是在WS-I (Web Service Interoperability) 组织成立后，为匹配WS-I 的 Web Service 标准，微软开发了强化Web Service 的增强包Web Service Enhancement (WSE)，最新版本为3.0 版（搭配 ASP.NET 2.0），可支持许多WS-I 的标准。
由于 Windows Communication Foundation 的推出，微软将Web Service 的发展重心移到WCF 上，原有的ASP.NET Web Service 即给定了一个名称：ASMX Web Service。

扩展

ASP.NET 在 2.0 版时，功能已大致底定，成为 Web 应用程序的基础架构，微软开始在ASP.NET 2.0 上开发扩展的功能，包括 AJAX 的支持、MVC架构的支持以及更容易开发出数据库应用的架构。

ASP.NET AJAX

ASP.NET AJAX 是微软发展的AJAX Framework，让 ASP.NET 的开发人员得以用很简单的方式就可以开发出支持AJAX (AJAX-enabled) 的应用程序，包含客户端脚本的支持，以及服务端的链接等等。

ASP.NET Dynamic Data Framework

ASP.NET Dynamic Data Framework 是微软在ASP.NET 3.5 中开发的一组类库，封装在System.Web.DynamicData 名字空间中，并且配合ASP.NET Routing Model（网页绕送功能）让开发人员可以很简单的开发出基于LINQ to SQL 或是ADO.NET Entity Framework 数据模型的数据库应用程序。

ASP.NET Routing

ASP.NET Routing Model（官方译名为ASP.NET 路由）是一个基于REST规格下的URL 对应机制，开发人员可以在服务端设置URL 的格式，用户可以用由开发人员定义的URL 格式浏览网页，ASP.NET 会自动将URL 转换成为内部的URL 格式，虽然它和URL Rewriting 很像，但微软认为ASP.NET Routing 不是 URL Rewriting。