ASP.NET 数据源

数据源

github:  https://github.com/ixixii/ASP.NET_03_WebForms

一个 data sourse 控件与数据绑定的控件相互作用,并隐藏了复杂的数据的联编过程。这些是提供数据给 data bound 控件的工具,并且支持如插入,删除和更新操作的执行。

每一个 data sourse 控件包裹了一个特殊的数据提供者相关的数据库,XML 文件,或者是自定义类,并且帮助:

  • 管理连接
  • 选择数据
  • 管理像分页,缓存等的展示方面
  • 操控数据

有许多可在 ASP.NET 中获得的 data sourse 控件,为从 SQL 服务器,ODBC 或者 OLE DB 服务器,从 XML 文件,和从业务对象中获得数据。

基于数据类型,这些控件能被分为两个种类:

  • 分层的 data sourse 控件
  • 基于表格的 data sourse 控件

用于分层数据的 data sourse 控件是:

  • XMLDataSource - 它允许用或者不用模式信息绑定 XML 文件和字符串。
  • SiteMapDataSource - 它允许绑定一个提供站点地图信息的提供者。

用作表格数据的 data source 控件是:

Data source 控件 描述
SqlDataSource 它表示到返回 SQL 数据的 ADO.NET data provider 的连接,包括通过 OLEDB 和 QDBC 可获得的 data sources。
ObjectDataSource 它允许绑定一个返回数据的自定义的 .Net business 对象
LinqdataSource 它允许绑定 Linq-t0-SQL 查询的结果。(仅由 ASP.NET 3.5 支持)
AccessDataSource 它表示到 Microsoft Access 数据库的连接。

Data Source 视图

Data source 视图是 DataSourceView 类的对象,它代表一个自定义的为不同数据操作如排序,过滤等而设计的数据视图。

DataSourceView 类作为所有 data source 视图类的基本类而使用,它定义了 data source 控件的性能。

以下表格提供了 DataSourceView 类的属性:

属性 描述
CanDelete 表示是否允许删除潜在的 data source。
CanInsert 表示是否允许插入潜在的 data source。
CanPage 表示是否允许给潜在的 data source 分页。
CanRetrieveTotalRowCount 表示总的行信息能否获得。
CanSort 表示数据是否能排序。
CanUpdate 表示是否允许在潜在的 data source 上更新。
Events 获得 data source 视图代表的事件句柄的列表。
Name 视图的名字。

以下的表格提供了 DataSourceView 类的方法:

方法 描述
CanExecute 确定指定的命令是否能执行。
ExecuteCommand 执行指定的命令。
ExecuteDelete 在 DataSourceView 对象所表示的数据列表上执行一个删除操作。
ExecuteInsert 在 DataSourceView 对象所表示的数据列表上执行一个插入操作。
ExecuteSelect 从潜在的数据存储中获取数据列表。
ExecuteUpdate 在 DataSourceView 对象所表示的数据列表上执行一个更新操作。
Delete 在和视图所联系的数据上执行一个删除操作。
Insert 在和视图所联系的数据上执行一个插入操作。
Select 返回被查询的数据。
Update 在和视图所联系的数据上执行一个更新操作。
OnDataSourceViewChanged 提出 DataSourceViewChanged 事件。
RaiseUnsupportedCapabilitiesError 由 RaiseUnsupportedCapabilitiesError 方法调用来将 ExecuteSelect 操作所需要的能力和视图所支持的能力相比较。

SqlDataSource 控件

SqlDataSource 控件代表到相关数据库比如 SQL Server 或者 Oracle数据库,或者通过 OLEDB 或 Open Database Connectivity(ODBC) 的可存取数据的连接。数据连接通过两个重要的属性 ConnectionString 和 ProviderName 完成。

以下的代码片段提供了控件的基本语法:

<asp:SqlDataSource runat="server" ID="MySqlSource"ProviderName='<%$ ConnectionStrings:LocalNWind.ProviderName  %>'ConnectionString='<%$ ConnectionStrings:LocalNWind %>'SelectionCommand= "SELECT * FROM EMPLOYEES" /><asp:GridView ID="GridView1" runat="server" DataSourceID="MySqlSource" />

在潜在的数据上配置不同的数据操作依赖于 data source 控件的不同属性(属性集)。

以下的表格提供了相关的 SqlDataSource 控件的属性集,它提供了控件的编程接口:

属性组 描述
DeleteCommand,
DeleteParameters,
DeleteCommandType
获取或设置 SQL 语句,参数和在潜在数据中删除行的类型。
FilterExpression,
FilterParameters
获取并设置数据过滤字符串和参数。
InsertCommand,
InsertParameters,
InsertCommandType
获取或设置 SQL 语句,参数和在潜在数据中插入行的类型。
SelectCommand,
SelectParameters,
SelectCommandType
获取或设置 SQL 语句,参数和在潜在数据中检索行的类型。
SortParameterName 获取或设置一个输入参数的名字,它将被命令存储的过程用来给数据排序。
UpdateCommand,
UpdateParameters,
UpdateCommandType
获取或设置 SQL 语句,参数和在潜在数据中更新行的类型。

以下的代码片段展示了能被用来做数据操作的 data source 控件:

<asp:SqlDataSource runat="server" ID= "MySqlSource"ProviderName='<%$ ConnectionStrings:LocalNWind.ProviderName  %>'ConnectionString=' <%$ ConnectionStrings:LocalNWind %>'SelectCommand= "SELECT * FROM EMPLOYEES"UpdateCommand= "UPDATE EMPLOYEES SET LASTNAME=@lame"DeleteCommand= "DELETE FROM EMPLOYEES WHERE EMPLOYEEID=@eid"FilterExpression= "EMPLOYEEID > 10">..........
</asp:SqlDataSource>

ObjectDataSource 控件

ObjectDataSource 控件使 user-defined 类能让它们方法的输出和 data bound 控件相连接。这个类的编程接口几乎和 SqlDataSource 控件相同。

以下是绑定客户对象的两个重要方面:

  • 可绑定的类应该拥有一个默认的构造函数,它应该是无状态的,并且拥有能够映射到选择,更新,插入,和删除语意的方法。
  • 对象必须一次更新一个项目,批处理操作是不支持的。

让我们直接到一个例子中来使用这个控件。student 类是被用来和一个 data source 对象一起使用的类。这个类有三个属性:a student id,name,和 city。它有一个默认的构造函数和一个检索数据的 GetStudents 方法。

student 类:

public class Student
{public int StudentID { get; set; }public string Name { get; set; }public string City { get; set; }public Student(){ }public DataSet GetStudents(){DataSet ds = new DataSet();DataTable dt = new DataTable("Students");dt.Columns.Add("StudentID", typeof(System.Int32));dt.Columns.Add("StudentName", typeof(System.String));dt.Columns.Add("StudentCity", typeof(System.String));dt.Rows.Add(new object[] { 1, "M. H. Kabir", "Calcutta" });dt.Rows.Add(new object[] { 2, "Ayan J. Sarkar", "Calcutta" });ds.Tables.Add(dt);return ds;}
}

采取以下的步骤来将对线绑定到一个 data source 对象和检索数据:

  • 创建一个新的网页。
  • 通过右击 Solution Explorer 的项目来给它添加一个类(Student.cs),添加一个类模板,将上面的代码放在里面。
  • 建立方法使得应用程序可以使用类的引用。
  • 在网页表单中放置一个 data source 控件对象。
  • 通过选择对象来配置 data source。

  • 给不同的数据操作选择数据方法。在这个例子中,仅有一个方法。

  • 在页面上放置一个 data bound 控件比如 grid view 并且选择 data source 对象作为潜在的 data source。

  • 在这个阶段,设计视图应该像以下这样:

  • 运行项目,它检索了 students 类中的硬编码的元祖。

AccessDataSource 控件

AccessDataSource 控件代表了到 Access 数据库的连接。它基于 SqlDataSource 控件并提供了更简单的编程接口。以下的代码片段提供了 data source 的基本语法:

<asp:AccessDataSource ID="AccessDataSource1 runat="server" DataFile="~/App_Data/ASPDotNetStepByStep.mdb" SelectCommand="SELECT * FROM  [DotNetReferences]">
</asp:AccessDataSource>

AccessDataSource 控件打开了只读模式的数据库。但是,它也能被用来执行插入,更新或者删除操作。这以使用 ADO.NET 命令和参数集合来完成。

更新对于 ASP.NET 应用程序内的 Access 数据库来说是有问题的,这是因为 Access 数据库是一个纯文本并且默认的 ASP.NET 应用程序账户可能有写数据库文件的权限。

ASP.NET 数据库存取

数据库存取

ASP.NET 允许存取和使用下列数据源:

  • 数据库(例如:Access、 SQL Server、 Oracle、 MySQL)
  • XML 文档
  • Business Objects
  • Flat files

ASP.NET 隐藏了复杂的数据存取过程并且提供了更为高级的类和对象,通过他们数据可以更容易的存取。

这些类隐藏了所有的连接,数据存取,数据检索和数据操纵的复杂的代码。

ADO.NET 技术提供了各种 ASP.NET 控件对象和后台数据之间的桥梁。

在本指导中,我们着眼于数据存取并且简单的介绍数据。

检索和显示数据

在 ASP.NET 中检索和显示数据需要两种类型的数据控制:

  • 数据源控制 - 它管理数据的连接、数据的选择和其他工作,例如数据的分页和缓存等等。
  • 数据显示控制 - 这将约束和显示数据并且允许操作数据。

我们将在以后详细探讨数据约束和数据源控制。

在本节中,我们将应用 SqlDataSource 控件存取数据。在本章用 GridView 控件显示和操作数据。

我们也会应用 Access 数据库,它包含了市场上有的 .Net 书籍的细节信息。

将我们的数据库命名为 ASPDotNetStepByStep.mdb 并且我们将应用名为 DotNetReferences 的数据表。

这张表包含了以下栏目:ID、Title、AuthorFirstName、AuthorLastName、Topic 和 Publisher。
下图是这个数据表的截图:

下面让我们直接按照下面步骤实践:

(1)创建一个网站并且在网页表格中添加 SqlDataSourceControl。

(2)单击 Configure Data Source 选项。

(3)点击 New Connection 按钮建立数据库连接。

(4)连接一旦建立,你就可以保存他们以备以后应用。下一步,你会被要求设置 select statement:

(5)选择好 columns 中的项目后点击 next 按钮完成剩余步骤。观察 WHERE, ORDER BY, 和 Advanced 按钮。这些按钮允许你执行 where 子句,order by 子句并且分别指定 SQL 中的插入,更新和删除命令。这样你就可以对数据进行操作了。

(6)在表中添加 GridView 控件。选择数据源并且用 AutoFormat 选项生成控件。

(7)在这之后设置的 GridView 控件可以显示栏目标题,这个程序就可以执行了。

(8)最后执行该程序。

以上涉及的代码列示如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="dataaccess.aspx.cs" Inherits="datacaching.WebForm1" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"><title>Untitled Page</title></head><body><form id="form1" runat="server"><div><asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString= "<%$   ConnectionStrings:ASPDotNetStepByStepConnectionString%>" ProviderName= "<%$ ConnectionStrings:ASPDotNetStepByStepConnectionString.ProviderName %>" SelectCommand="SELECT [Title], [AuthorLastName], [AuthorFirstName], [Topic] FROM [DotNetReferences]"></asp:SqlDataSource><asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4" DataSourceID="SqlDataSource1" ForeColor="#333333" GridLines="None"><RowStyle BackColor="#F7F6F3" ForeColor="#333333" /><Columns><asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" /><asp:BoundField DataField="AuthorLastName" HeaderText="AuthorLastName" SortExpression="AuthorLastName" /><asp:BoundField DataField="AuthorFirstName" HeaderText="AuthorFirstName" SortExpression="AuthorFirstName" /><asp:BoundField DataField="Topic" HeaderText="Topic" SortExpression="Topic" /></Columns><FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /><PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" /><SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" /><HeaderStyle BackColor="#5D7B9D" Font-Bold="True"  ForeColor="White" /><EditRowStyle BackColor="#999999" /><AlternatingRowStyle BackColor="White" ForeColor="#284775" /></asp:GridView></div></form></body>
</html>

ASP.NET 数据绑定

ASP.NET - 数据绑定

每一个 ASP.NET 网页表单控件从它的父控件类继承了 DataBind 方法,它给予了它继承的能力来绑定数据到它属性中的至少一个属性。这就是所谓的简单数据绑定或者内部数据绑定

简单数据绑定包括将任何实现 IEnumerable 接口的集合(项目集合),或者 DataSet 和 DataTable 类附加到控件的 DataSource 属性。

另一方面,一些控件可以通过 DataSource 控件绑定记录,列表,或者数据列到它们的结构中。这些控件源自 BaseDataBoundControl 类。这被叫做描述性数据绑定

data source 控件帮助 data-bound 控件实现了比如排序,分页和编辑数据集合的功能。

BaseDataBoundControl 是一个抽象类,它通过两个抽象类继承:

  • DataBoundControl
  • HierarchicalDataBoundControl

抽象类 DataBoundControl 也由两个抽象类继承:

  • ListControl
  • CompositeDataBoundControl

能够简单绑定数据的控件源自 ListControl 抽象类并且这些控件是:

  • BulletedList
  • CheckBoxList
  • DropDownList
  • ListBox
  • RadioButtonList

能够描述性数据绑定的控件(一个更复杂的数据绑定)源自抽象类 CompositeDataBoundControl。这是控件是:

  • DetailsView
  • FormView
  • GridView
  • RecordList

简单数据绑定

简单数据绑定包括只读选择列表。这些控件能绑定一个数组列或者数据库的字段。选择列表从数据库中或 data source 中取两个值;一个值用过列表表示而另一个被认为是相应显示的值。

让我们使用一个小例子来理解这个概念。用一个项目符号列表和一个 SqlDataSource 控件来创建一个网页。配置 data source 控件来从你的数据库中(我们在之前的章节中使用相同的 DotNetReferences 表)检索两个值。

为包含的项目符号列表控件选择一个 data source:

  • 选择 data source 控件
  • 选择一个字段来展示,它被叫做数据字段
  • 选择值的字段

当应用程序执行的时候,检查整个标题列绑定到项目符号列表并被展示。

描述性数据绑定

我们已经在之前的指南中使用 GridView 控件来使用描述性数据绑定。其他复合的能够以表格的方式展示并操作数据的 data bound 控件是 DetailsView, FormView 和 RecordList 控件。

在下一个指南中,我们将研究解决数据库,i.e,ADO.NET 的 技术。

但是,数据绑定包括以下对象:

  • 存储从数据库检索数据的数据集。
  • 数据提供者,它通过使用一个连接的命令从数据库中检索数据。
  • 发出存储在 command 对象中的选择语句的数据适配器;它也能通过发出 Insert,Delete,和 Updata 语句来更新数据库中的数据。

data bonding 对象间的关系:

例子

让我们采取以下的步骤:

步骤(1):创建一个新的网页。通过右击在 Solution Explorer 上的 solution 名字和从 'Add Item' 对话框中选择项目 'Class' 来添加一个名为 booklist 的类。将它命名为 booklist.cs。

using System;
using System.Data;
using System.Configuration;
using System.Linq;using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;namespace databinding
{public class booklist{protected String bookname;protected String authorname;public booklist(String bname, String aname){this.bookname = bname;this.authorname = aname;}public String Book{get{return this.bookname;}set{this.bookname = value;}}public String Author{get{return this.authorname;}set{this.authorname = value;}}}
}

步骤(2):在页面上添加四个列表控件,一个 list box 控件,一个 radio button 控件,一个 check box 控件和一个 drop down list 和四个与这些列表控件一起的四个表单。在设计视图中页面应该看起来像这样:

源文件应该看起来像下面这样:

<form id="form1" runat="server"><div><table style="width: 559px"><tr><td style="width: 228px; height: 157px;"><asp:ListBox ID="ListBox1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"></asp:ListBox></td><td style="height: 157px"><asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"></asp:DropDownList></td>             </tr><tr><td style="width: 228px; height: 40px;"><asp:Label ID="lbllistbox" runat="server"></asp:Label></td><td style="height: 40px"><asp:Label ID="lbldrpdown" runat="server"></asp:Label></td></tr><tr><td style="width: 228px; height: 21px"></td><td style="height: 21px"></td>              </tr><tr><td style="width: 228px; height: 21px"><asp:RadioButtonList ID="RadioButtonList1" runat="server"AutoPostBack="True"  OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged"></asp:RadioButtonList></td><td style="height: 21px"><asp:CheckBoxList ID="CheckBoxList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="CheckBoxList1_SelectedIndexChanged"></asp:CheckBoxList></td>                </tr><tr><td style="width: 228px; height: 21px"><asp:Label ID="lblrdlist" runat="server"></asp:Label></td><td style="height: 21px"><asp:Label ID="lblchklist" runat="server"></asp:Label></td>           </tr></table>      </div>
</form>

步骤(3):最后,在应用程序的例行程序后写下面的代码:

public partial class _Default : System.Web.UI.Page
{protected void Page_Load(object sender, EventArgs e){IList bklist = createbooklist();if (!this.IsPostBack){this.ListBox1.DataSource = bklist;this.ListBox1.DataTextField = "Book";this.ListBox1.DataValueField = "Author";this.DropDownList1.DataSource = bklist;this.DropDownList1.DataTextField = "Book";this.DropDownList1.DataValueField = "Author";this.RadioButtonList1.DataSource = bklist;this.RadioButtonList1.DataTextField = "Book";this.RadioButtonList1.DataValueField = "Author";this.CheckBoxList1.DataSource = bklist;this.CheckBoxList1.DataTextField = "Book";this.CheckBoxList1.DataValueField = "Author";this.DataBind();}}protected IList createbooklist(){ArrayList allbooks = new ArrayList();booklist bl;bl = new booklist("UNIX CONCEPTS", "SUMITABHA DAS");allbooks.Add(bl);bl = new booklist("PROGRAMMING IN C", "RICHI KERNIGHAN");allbooks.Add(bl);bl = new booklist("DATA STRUCTURE", "TANENBAUM");allbooks.Add(bl);bl = new booklist("NETWORKING CONCEPTS", "FOROUZAN");allbooks.Add(bl);bl = new booklist("PROGRAMMING IN C++", "B. STROUSTROUP");allbooks.Add(bl);bl = new booklist("ADVANCED JAVA", "SUMITABHA DAS");allbooks.Add(bl);return allbooks;}protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e){this.lbllistbox.Text = this.ListBox1.SelectedValue;}protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){this.lbldrpdown.Text = this.DropDownList1.SelectedValue;}protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e){this.lblrdlist.Text = this.RadioButtonList1.SelectedValue;}protected void CheckBoxList1_SelectedIndexChanged(object sender, EventArgs e){this.lblchklist.Text = this.CheckBoxList1.SelectedValue;}
}

观察以下:

  • booklist 类有两个属性:bookname 和 authorname。
  • createbooklist 方法是一个用户定义的可以创建名为 allboods 的 booklist 类的数组的方法。
  • Page_Load 事件句柄确保了 books 的列表被创建。该列表是 IList 型的,它实现了 IEnumerable 接口并能和列表控件绑定。Page load 时间句柄用控件绑定了 IList 对象'bklist'。bookname 属性被展示并且 authorname 属性被视为这个值。  
  • 当页面运行时,如果用户选择了一本书,则它的名字被选择并且通过 list 控件被显示出来,而相应的标签显示作者的名字,它是 list 控件所选择的相应的值。

ASP.NET 自定义控件

自定义控件

ASP.NET 允许用户创建控件。这些用户定义的控件被分类为:

  • 用户控件
  • 自定义控件

用户控件  

用户控件行为像微型 ASP.NET 页面或者网页表单,它能被许多其他页面使用。这些都是源自 System.Web.UI.UserControl 类。这些控件有下列特性:

  • 它们有 .ascx 扩展。
  • 它们可能不会含有任何 , 或者 标签。
  • 它们有一个 Control 指令而不是一个 Page 指令。

为了理解这个概念,让我们创建一个简单的用户控件,它将作为 web 页面的页脚使用。为了创建和使用用户控件,采取以下步骤:

  • 创建一个新的 web 应用程序。
  • 在 Solution Explorer 上右击项目文件夹并且选择 ADD New Item。

  • 从 Add New Item 对话框中选择 Web User Control 并且把它命名为 footer.ascx。最初,footer.ascx 仅含有一个 Control 指令。
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="footer.ascx.cs" Inherits="customcontroldemo.footer" %>
  • 给文件添加下列代码:
<table><tr><td align="center"> Copyright ©2010 TutorialPoints Ltd.</td></tr><tr><td align="center"> Location: Hyderabad, A.P </td></tr>
</table>

为给你的 web 网页添加用户控件,你必须添加 Register 指令和一个页面用户控件的实例。以下的代码展示了说明:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="customcontroldemo._Default" %><%@ Register Src="~/footer.ascx" TagName="footer" TagPrefix="Tfooter" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"><title>Untitled Page</title></head><body><form id="form1" runat="server"><div><asp:Label ID="Label1" runat="server" Text="Welcome to ASP.Net Tutorials "></asp:Label><br />  <br /><asp:Button ID="Button1" runat="server" onclick="Button1_Click"  Text="Copyright Info" /></div><Tfooter:footer ID="footer1" runat="server" /></form></body>
</html>

当执行后,页面显示了页脚而且这个控件能在所有你的网站的页面中被使用。

观察以下:

(1)Register 指令为控件指定了一个标签名称和标签前缀。

<%@ Register Src="~/footer.ascx" TagName="footer" TagPrefix="Tfooter" %>

(2)下列的标签名称和前缀应该在页面上添加用户控件时被使用:

<Tfooter:footer ID="footer1" runat="server" />

自定义控件

自定义控件被部署为单独的集合。它们被编译成动态链接库(DLL)并且作为任何其他的 ASP.NET 服务控件来使用。它们能被以下方法中的任何一个来创建:

  • 通过从一个存在的控件中获得一个自定义控件。
  • 通过联合两个或者更多的存在的控件来组成一个新的自定义控件。
  • 通过从基本的控件类中获得。

为了理解这个概念,让我们创建一个自定义类,它将简单地在浏览器上呈现一条短信。为了创建控件,采取以下步骤:

创建一个新的网站。在 Solution Explorer 中树的顶端右击 solution(不是项目)。

在 New Project 对话框中,从项目模板中选择 ASP.NET Server Control。

上面的步骤添加了一个新的项目并且给 solution 创建了一个完整的自定义控件,叫做 ServerControl1。在这个例子中,让我命名 CustomControls 项目。为了使用这个控件,它必须在页面上注册之前作为引用添加到网页中。为了添加引用到已存在的项目中,右击项目(不是 solution),并且点击 Add Reference。

从 Add Reference 对话框中的 Projects 标签选择 CustomControl 项目。Solution Explorer 能显示引用。

为了在页面上使用控件,在 @Page 指令下添加 Register 指令。

<%@ Register Assembly="CustomControls"  Namespace="CustomControls"  TagPrefix="ccs" %>

而且,你可以使用控件,和任何其他控件类似。

<form id="form1" runat="server"><div><ccs:ServerControl1 runat="server" Text = "I am a Custom Server Control" /></div>
</form>

当执行后,控件的 Text 属性被展示在浏览器上,如下所示:

使用自定义类

在之前的例子中,自定义类的 Text 属性值被设置了。当控件被创建时,ASP.NET 默认添加了这个属性。以下控件的文件后的代码揭示了这个。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace CustomControls
{[DefaultProperty("Text")][ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1 >")]public class ServerControl1 : WebControl{[Bindable(true)][Category("Appearance")][DefaultValue("")][Localizable(true)]public string Text{get{String s = (String)ViewState["Text"];return ((s == null) ? "[" + this.ID + "]" : s);}set{ViewState["Text"] = value;}}protected override void RenderContents(HtmlTextWriter output){output.Write(Text);}}
}

上述的代码自动生成给一个自定义控件。事件和方法能被添加到 custom control 类中。

例子

让我们扩展之前的名为 ServerControl1 的自定义控件。让我们给予它一个名为 checkpalindrome 的方法,它将给它权限来检查 palindrome。

Palindrome 是当颠倒时仍拼写相同的文字/字面值。例如,Malayalam,madam,saras 等。

扩展自定义控件的代码,它应该看起来如下所示:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace CustomControls
{[DefaultProperty("Text")][ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1  >")]public class ServerControl1 : WebControl{[Bindable(true)][Category("Appearance")][DefaultValue("")][Localizable(true)]public string Text{get{String s = (String)ViewState["Text"];return ((s == null) ? "[" + this.ID + "]" : s);}set{ViewState["Text"] = value;}}protected override void RenderContents(HtmlTextWriter output){if (this.checkpanlindrome()){output.Write("This is a palindrome: <br />");output.Write("<FONT size=5 color=Blue>");output.Write("<B>");output.Write(Text);output.Write("</B>");output.Write("</FONT>");}else{output.Write("This is not a palindrome: <br />");output.Write("<FONT size=5 color=red>");output.Write("<B>");output.Write(Text);output.Write("</B>");output.Write("</FONT>");}}protected bool checkpanlindrome(){if (this.Text != null){String str = this.Text;String strtoupper = Text.ToUpper();char[] rev = strtoupper.ToCharArray();Array.Reverse(rev);String strrev = new String(rev);if (strtoupper == strrev){return true;}else{return false;}}else{return false;}}}
}

当你改变空间的代码时,你必须通过点击 Build --> Build Solution 来构建方法,这样改变才能反映在你的项目中。给页面添加一个 text box 和一个 button 控件,这样用户才能提供一段 text。当 button 被点击时,它就被用来检查 palindrome。

<form id="form1" runat="server"><div>Enter a word:<br /><asp:TextBox ID="TextBox1" runat="server" style="width:198px"> </asp:TextBox><br /> <br /><asp:Button ID="Button1" runat="server onclick="Button1_Click" Text="Check Palindrome" style="width:132px" /><br /> <br /><ccs:ServerControl1 ID="ServerControl11" runat="server" Text = "" /></div>
</form>

button 的 Click 事件句柄简单地将 text box 中的 text 复制到自定义控件的 text 属性中。

protected void Button1_Click(object sender, EventArgs e)
{this.ServerControl11.Text = this.TextBox1.Text;
}

当被执行后,控件成功地检测到了 palindromes。

观察以下:

(1) 当你给自定义控件添加一个引用时,它被添加到 toolbox 并且你可以像其他控件一样从 toolbox 中直接使用它。

(2)custom control 类的 RenderContents 方法被覆写了,你可以添加你自己的方法和事件。

(3)RenderContents 方法采用了 HtmlTextWriter 型的参数,它将对在浏览器上展示负责。

ASP.NET 个性化

个性化

网站是为用户的重复访问而设计的。个性化允许一个网站记住用户标识和其他信息细节,并且它给每个用户提供了一个个人的环境。

ASP.NET 为满足特性客户的品味和喜好而个性化一个网站提供服务。

理解特征文件

ASP.NET 个性化服务基于用户的特征文件。用户特征文件定义了该网站需要用户的信息。例如,名字,年龄,地址,出生日期和手机号码。

这个信息被定义在应用程序的 web.config 文件中并且 ASP.NET 运行时间阅读并使用它。这个工作由个性化提供者所完成。

用户数据所含有的用户特征文件被存储在默认的 ASP.NET 创建的数据库中。你可以创建你自己的数据库来存储特征文件。特征文件数据定义被存储在配置文件 web.config 中。

例子

让我们创建一个样本网站,那里我们想要我们的应用程序记住用户细节,像名字,地址,出生日期等。在 web.config 文件中用 元素添加特征文件细节。

<configuration>
<system.web><profile><properties><add name="Name" type ="String"/><add name="Birthday" type ="System.DateTime"/><group name="Address"><add name="Street"/><add name="City"/><add name="State"/><add name="Zipcode"/></group></properties>
</profile></system.web>
</configuration>

当特征文件在 web.config 文件中被定义时,特征文件可以通过在当前的 HttpContext 中找到的 Profile 属性使用并且通过页面获得。

添加 text box 来获取在特征文件中定义的用户输入,添加一个 button 来提交数据:

更新 Page_load 来展示特征文件信息:

using System;
using System.Data;
using System.Configuration;using System.Web;
using System.Web.Security;using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;public partial class _Default : System.Web.UI.Page
{protected void Page_Load(object sender, EventArgs e){if (!this.IsPostBack){ProfileCommon pc=this.Profile.GetProfile(Profile.UserName);if (pc != null){this.txtname.Text = pc.Name;this.txtaddr.Text = pc.Address.Street;this.txtcity.Text = pc.Address.City;this.txtstate.Text = pc.Address.State;this.txtzip.Text = pc.Address.Zipcode;this.Calendar1.SelectedDate = pc.Birthday;}}}
}

为提交按钮写以下的句柄,将用户数据存入特征文件中:

protected void btnsubmit_Click(object sender, EventArgs e)
{ProfileCommon pc=this.Profile.GetProfile(Profile.UserName);if (pc != null){pc.Name = this.txtname.Text;pc.Address.Street = this.txtaddr.Text;pc.Address.City = this.txtcity.Text;pc.Address.State = this.txtstate.Text;pc.Address.Zipcode = this.txtzip.Text;pc.Birthday = this.Calendar1.SelectedDate;pc.Save();}
}

当页面第一次执行时,用户需要输入信息。但是,下一次用户的细节将被自动加载。

元素的属性

除了我们已经使用过的名字和类型属性,元素还有其它属性。以下的表格展示了这些属性中的一些:

属性 描述
name 属性的名字。
type 类型默认是 string 但是它允许任何完全的类名称作为数据类型。
serializeAS 当序列化这个值时使用的格式。
readOnly 只读的特征文件值不能被改变,这个属性默认是 false。
defaultValue 一个默认的值,如果特征文件不存在或者没有信息的话它被使用。
allowAnonymous 一个指示这个属性是否能和匿名文件使用的布尔值。
Provider 应该被用来管理这个属性的特征文件提供者。

匿名个性化

匿名个性化允许用户在标识它们自己之前个性化网站。例如,Amazon.com 允许用户在登录前在购物车中添加物品。为了启用此功能,web.config 文件可以被配置成以下:

<anonymousIdentification enabled ="true" cookieName=".ASPXANONYMOUSUSER"cookieTimeout="120000" cookiePath="/" cookieRequiresSSL="false"cookieSlidingExpiration="true" cookieprotection="Encryption"coolieless="UseDeviceProfile"/>

ASP.NET 异常处理

异常处理

在 ASP.NET 中异常处理有三个方面:

  • Tracing - 在页面级  或者  应用程序级  追踪程序执行。
  • Error handling - 在页面级   或者   应用程序级   解决标准错误或者自定义错误。
  • Debugging - 在程序中前进,设置断点来分析代码。

在这一章中,我们将讨论 tracing 和 handling。

并且在这一章中,我们将涉及 debugging。

为了理解概念,创建以下的样本应用程序。它有一个 label 控件,一个 dropdown 列表和一个链接。dropdown 列表加载了一个名言的 array 列表并且被选择的引用将显示在下面的标签中。它也拥有一个超链接,它指向一个不存在的链接。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="errorhandling._Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"><title>Tracing, debugging and error handling</title></head><body><form id="form1" runat="server"><div><asp:Label ID="lblheading" runat="server" Text="Tracing, Debuggin  and Error Handling"></asp:Label><br /> <br /><asp:DropDownList ID="ddlquotes" runat="server" AutoPostBack="True"  onselectedindexchanged="ddlquotes_SelectedIndexChanged"></asp:DropDownList><br /> <br /><asp:Label ID="lblquotes" runat="server"></asp:Label><br /> <br /><asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="mylink.htm">Link to:</asp:HyperLink></div></form></body></html>

文件后的代码:

public partial class _Default : System.Web.UI.Page
{protected void Page_Load(object sender, EventArgs e){if (!IsPostBack){string[,] quotes = {{"Imagination is more important than Knowledge.", "Albert Einsten"},{"Assume a virtue, if you have it not" "Shakespeare"},{"A man cannot be comfortable without his own approval", "Mark Twain"},{"Beware the young doctor and the old barber", "Benjamin Franklin"},{"Whatever begun in anger ends in shame", "Benjamin Franklin"}};for (int i=0; i<quotes.GetLength(0); i++)ddlquotes.Items.Add(new ListItem(quotes[i,0], quotes[i,1]));}}protected void ddlquotes_SelectedIndexChanged(object sender, EventArgs e){if (ddlquotes.SelectedIndex != -1){lblquotes.Text = String.Format("{0}, Quote: {1}", ddlquotes.SelectedItem.Text, ddlquotes.SelectedValue);}}
}

Tracing

为了允许页面级别的追踪,你需要修改 Page 指令并且如下添加一个 Trace 属性:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"Inherits="errorhandling._Default" Trace ="true" %>

现在当你执行文件时,你将得到追踪信息:

它在首部提供了以下的信息:

  • Session ID
  • Status Code
  • Time of Request
  • Type of Request
  • Request and Response Encoding

每次页面被需要时,从服务器发出的 status 代码显示名字和错误时间,如果有的话。以下的表格显示普通的 HTTP status 代码:

数字 描述
通知(100 - 199)
100 继续
101 转换协议
成功(200 - 299)
200 OK
204 无内容
重定向(300 - 399)
301 永久移动
305 使用代理
307 暂时重定向
来自客户端的错误(400 - 499)
400 错误请求
402 支付需求
404 未找到
408 请求超时
417 期望失败
来自服务器的错误(500 - 599)
500 内部服务器错误
503 服务不可用
505 HTTP 版本不支持

在顶级信息下,有一个 Trace 日志,它提供了页面生命周期的细节。它提供了页面被初始化后的以秒为单位的运行时间。

下一个部分是控件树,它以分层的形式列举了页面上所有的控件:

Session 和 Application 中的最后声明了跟随了所有服务器变量的 summaries,cookies 和 headers 集合。

Trace 对象允许你给 trace 输出添加自定义信息。它有两个方法来完成:Write 方法和 Warn 方法。

改变 Page_Load 事件句柄在检测 Write 方法:

protected void Page_Load(object sender, EventArgs e)
{Trace.Write("Page Load");if (!IsPostBack){Trace.Write("Not Post Back, Page Load");string[,] quotes = .......................}
}

运行来观察影响:

为了检测 Warn 方法,让我们在被选择的 index changed 事件句柄中强制输入一些错误的代码:

try
{int a = 0;int b = 9 / a;
}catch (Exception e)
{Trace.Warn("UserAction", "processing 9/a", e);
}

Try-Catch 是一个 C# 编程结构。try 块持有任何可以或不可以产生错误的代码,catch 块捕获了错误。当程序运行时,它在 trace 日志中发送警告。

应用程序层次的追踪应用到网站中的所有的页面。它通过将以下代码放入 web.config 文件被实现:

<system.web><trace enabled="true" />
</system.web>

错误解决

尽管 ASP.NET 能检测所有的运行时错误,仍然有一些微小的错误仍在那儿。通过追踪观察错误是为开发者准备的,而不是用户。

因此,为了拦截这样情况的发生,你可以在应用程序的 web.config 中添加错误解决设置。它是应用程序范围的错误解决。例如,你可以在 web.config 文件中添加以下的代码:

<configuration><system.web><customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"><error statusCode="403" redirect="NoAccess.htm"    /><error statusCode="404" redirect="FileNotFound.htm" /></customErrors></system.web>
<configuration>

部分有可能的属性: - **Mode:**它允许或者不允许自定义错误页面。它有三个可能的值: - **On:**展示自定义页面。 - **Off:**展示 ASP.NET 错误页面(黄色页面) - **remoteOnly:**它展示了自定义错误到客户端,展示本地的 ASP.NET 错误。- **defaultRedirect:**它含有页面的 URL 来展示以备不能解决的错误。 为了给不同错误类型放置不同的自定义错误页面,子标签被使用,那里不同的错误页面基于错误的 status 代码被指定。 为了实现页面级别的错误解决,Page 指令能被修改为: `````` 因为 ASP.NET Debugging 是它内部一个重要的主题,因此我们将在下一章单独地讨论它。

ASP.NET 调试

调试

Debugging 可以让开发人员一步一步的看到代码是怎样工作的,变量的值是如何变化的和对象是怎样被创建又是怎样被销毁的等等。

当一个网页第一次被运行时,Visual Studio 会弹出一个提示框来询问 Debugging 是否需要被启用:

当 debugging 被启用时,下面几行代码将在 web.config 文件中出现:

<system.web>  <compilation debug="true">  <assemblies>  ..............  </assemblies>  </compilation>
</system.web>  

Debugging 工具栏会提供所有 debugging 所需的工具:

断点

断点规定程序在运行时在运行完指定的代码行之后立即停止运行,这样可以测试代码并且完成各种各样的 debugging 工作,例如,观察变量值的变化,单步调试代码,函数方法的跳入跳出等。
在代码上单击右键选择插入一个间断点来设置断点。然后在左边会出现一个红点并且该行代码被高亮显示,效果如图所示:

之后你运行这段代码,将会观察到断点的行为。

在这个阶段,你可以单步调试代码,观察运行的流程和变量值、属性、对象等。

如果你需要修改断点属性,你可以在断点标志上单击右键,在“属性”菜单中找到:

location 对话框显示文件所在位置,以及所选中的代码所在行数和字符数。condition 菜单允许你输入一个有效的表达式来估算程序是否运行到了断点:

Hit Count 菜单显示一个对话框来显示断点被运行的次数。

点击下拉菜单中的任何一个选项会打开一个用来输入命中次数的编辑框。这在分析循环结构的代码时非常有用。

Filter 菜单允许设置一个对特定机制、过程、线程或是任何组合的过滤使断点对它们生效。

When Hit 菜单允许你来指定当断点命中时的动作。

Debug 窗口

Visual Studio 提供下面的 debug 窗口,其中每一个都显示一些程序信息。下表列出了一些窗口:

窗口 描述
直接 显示变量和表达式。
自动 显示当前所有变量以及之前的状态。
本地 显示当前上下文的所有变量。
观察 显示多达四个不同集合的变量。
调用栈 显示调用栈中的所有方法。
线程 显示并控制线程。

ASP.NET 语言集成查询

语言集成查询

大多数应用都是以数据为中心的,然而大多数的数据仓库是关系型数据库。这些年,设计者和开发者设计了基于对象模型的应用程序。

对象来负责连接访问数据的组件——称为数据访问层( DAL )。这里我们需要考虑三点:

  • 一个应用程序所需要的所有数据可以不存储在一个资源中。这个资源可以是关系型数据库、业务对象、XML文件或者一个WEB服务器。
  • 访问内存中的对象要比访问数据库、XML文件中的数据更简单,更廉价。
  • 被访问到的数据不是直接使用的,而是被转存、排序、分组、修改等。

因此如果存在只是用几行代码就能实现轻易整合各种各样的数据——可以整合来自不同源的数据,并且能够执行基本的数据操作的工具,那将非常有用。

语言集成查询( LINQ )就是上述那样的一种工具。 LINQ 是 .NET Framework 3.5 的一个扩展集并且它的管理语言使查询更类似于是一种对象。它定义了一种通用的语法和程序模型,使我们可以使用一种惯用的语法完成查找不同类型的数据。

相关操作像查找、工程、链接、分组、分区、集合操作等可以在 LINQ 中使用,并且在 .NET Framework 3.5 中的 C# 和 VB 编译器支持 LINQ 的语法,这就使得它可以通过配置数据来存储,而不需要求助于 ADO.NET。

举个例子,在 Northwind 数据库中查询 Constomers 这张表,使用 C# 中的 LINQ ,代码应该是这样:

var data = from c in dataContext.Customers
where c.Country == "Spain"
select c;

其中:

  • from关键字逻辑上依次通过每个集合。
  • 包含关键字where的表达式会比较集合中的每个对象。
  • select声明会选择被比较出的对象加入到列表中并返回。
  • 关键字var用于变量声明。因为返回对象的准确类型不明确,它表明信息需要被动态的推测。

LINQ 查询语句可以应用在任何继承于 IEnumerable 的有数据支撑的类,这里 T 可以是任何一个数据类型,例如 List< Book >。

让我们来看一个示例理解一下概念。示例中使用了如下类:Book.cs

public class Books
{public string ID {get; set;}public string Title { get; set; }public decimal Price { get; set; }public DateTime DateOfRelease { get; set; }public static List<Books> GetBooks(){List<Books> list = new List<Books>();list.Add(new Books { ID = "001", Title = "Programming in C#", Price = 634.76m, DateOfRelease = Convert.ToDateTime("2010-02-05") });list.Add(new Books { ID = "002", Title = "Learn Jave in 30 days", Price = 250.76m, DateOfRelease = Convert.ToDateTime("2011-08-15") });list.Add(new Books { ID = "003", Title = "Programming in ASP.Net 4.0", Price = 700.00m, DateOfRelease = Convert.ToDateTime("2011-02-05") });list.Add(new Books { ID = "004", Title = "VB.Net Made Easy", Price = 500.99m, DateOfRelease = Convert.ToDateTime("2011-12-31") });list.Add(new Books { ID = "005", Title = "Programming in C", Price = 314.76m, DateOfRelease = Convert.ToDateTime("2010-02-05") });list.Add(new Books { ID = "006", Title = "Programming in C++", Price = 456.76m, DateOfRelease = Convert.ToDateTime("2010-02-05") });list.Add(new Books { ID = "007", Title = "Datebase Developement", Price = 1000.76m, DateOfRelease = Convert.ToDateTime("2010-02-05") });return list;}
}

在 web 网页中使用这个类要有简单的标签控制,来显示书的标题。Page_Load 方法创建了一个书的列表并且通过使用 LINQ 查询返回标题:

public partial class simplequery : System.Web.UI.Page
{protected void Page_Load(object sender, EventArgs e){List<Books> books = Books.GetBooks();var booktitles = from b in books select b.Title;foreach (var title in booktitles)lblbooks.Text += String.Format("{0} <br />", title);}
}

当网页被运行,标签显示查询结果:

上面的 LINQ 表达式:

var booktitles =
from b in books
select b.Title;

等价于下述 SQL 语句:

SELECT Title from Books

LINQ 运算符

除了到目前为止使用过的运算符之外,还有很多其他运算符来执行查询子句。我们来看一些运算符和子句。

join 子句

SQL 中的‘join clause’用来连接两个数据表并显示在两个数据表中都出现的列中的数据集合。LINQ 也可以支持这种功能。为了检测这一点,在之前的工程里增加另一个类名为 Saledetails.cs:

public class Salesdetails
{public int sales { get; set; }public int pages { get; set; }public string ID {get; set;}public static IEnumerable<Salesdetails> getsalesdetails(){ Salesdetails[] sd = {new Salesdetails { ID = "001", pages=678, sales = 110000},new Salesdetails { ID = "002", pages=789, sales = 60000},new Salesdetails { ID = "003", pages=456, sales = 40000},new Salesdetails { ID = "004", pages=900, sales = 80000},new Salesdetails { ID = "005", pages=456, sales = 90000},new Salesdetails { ID = "006", pages=870, sales = 50000},new Salesdetails { ID = "007", pages=675, sales = 40000},};return sd.OfType<Salesdetails>();}
}

在 Page_Load 函数中添加代码来用 join 子句处理在两张表里完成查询:

protected void Page_Load(object sender, EventArgs e)
{IEnumerable<Books> books = Books.GetBooks();IEnumerable<Salesdetails> sales = Salesdetails.getsalesdetails();var booktitles = from b in books join s in sales on b.ID equals s.IDselect new { Name = b.Title, Pages = s.pages };foreach (var title in booktitles)lblbooks.Text += String.Format("{0} <br />", title);
}

结果页显示如下:

where 子句

where 子句允许在查询中添加筛选条件。例如,如果你想获得页数多于 500 的书目,可以改变 Page_Load 方法中的句柄成下述样子:

var booktitles = from b in books join s in sales on b.ID equals s.IDwhere s.pages > 500 select new { Name = b.Title, Pages = s.pages };

查询语句只返回那些页数大于 500 的列:

正序倒序排序子句

这些子句允许将查询结果进行排序。为了查询出标题、页数和书的价格,并且按照价格排序,在 Page_Load 方法中的句柄里写如下代码:

var booktitles = from b in books join s in sales on b.ID equals s.IDorderby b.Price select new { Name = b.Title,  Pages = s.pages, Price = b.Price};

返回的元组是:

Let 子句

let 子句允许定义一个变量并且将数据计算的一个值赋给它。举个例子,计从上述两个销售值中计算总销售值,你需要这样计算:

TotalSale = Price of the Book * Sales

为了完成这个算式,加入下面这个代码片段在 Page_Load 方法的句柄里:

let 子句允许定义一个变量并且将数据计算的一个值赋给它。举个例子,计从上述两个销售值中计算总销售值,你需要这样计算:

var booktitles = from b in book join s in sales on b.ID equals s.IDlet totalprofit = (b.Price * s.sales)select new { Name = b.Title, TotalSale = totalprofit};

查询结果如下图所示:

ASP.NET 数据缓存

数据缓存

什么是缓存?

缓存是一种将经常使用的数据/信息存储在内存中的技术,这样,下次需要相同的数据/信息时,可以直接从内存检索,而不是再从应用程序中生成。

缓存在用于提高 ASP 性能方面是非常重要的,因为 ASP 的页面和控件是都动态生成的。这对于交互相关的数据是极其重要的,因为响应时间是很宝贵的。

在需要快速访问的媒体,如计算机的随机存取存储器,缓存放置了被频繁使用的数据。ASP 的运行时间包含一个叫做缓存的 CLR 对象的键值对。它位于应用程序内,并且通过 HttpContext 和 System.Web.UI.Page 可用。

在某些方面,缓存和存储状态对象有相似之处。然而,状态对象的存储信息是确定的,比如,你可以计算存储在状态对象的数据,但是缓存的数据是不确定的。

在下列情况里,数据是不可用的:

  • 如果它的生命周期已结束,
  • 如果该应用释放了它的内存,
  • 如果由于某些原因缓存没有被替换。

您可以使用一个索引器在缓存中访问项目,并且有可能控制缓存中对象的生命周期和设置缓存的对象及其物理资源之间的联系。

ASP.NET 中的缓存

ASP提供如下几种不同类型的缓存:

  • 输出缓存:输出缓存可以存储最后显现的网页的副本,或者是发送到客户机的部分页面。下次客户机请求该页面时,这个页面的缓存副本就会被发送给客户机,而不是重新生成这个页面,这样一来就节省了时间。
  • 数据缓存:数据缓存是指从数据源缓存数据。只要缓存没被替换,那么再请求该数据时就会从缓存中获取。当缓存被替换的时候,会从数据源中获取新数据,缓存也会被再次充满。
  • 对象缓存:对象缓存是缓存页面的对象,比如数据绑定控件等。缓存的数据放在服务器的内存。
  • 类缓存:网页或 Web 服务是第一次运行时在组装编译成页类。然后组装会在服务器缓存。当下次请求该页面或者服务,就会使用缓存的装配。当改变源代码时,CLR 重新编译程序集。
  • 配置缓存:应用程序配置信息存储在一个配置文件。配置缓存存储在服务器内存配置信息。

在本教程中,我们将考虑输出缓存,数据缓存和对象缓存。

输出缓存

呈现一个页面可能涉及一些复杂的过程,如,数据库访问,呈现复杂的控件等。输出缓存允许通过在内存中缓存数据,而绕过往返服务器。甚至可以缓存整个页面。

OutputCache 指令负责输出缓存。它启用输出缓存,并对其行为提供一定程度的控制。

OutputCache 指令的语法:

<%@ OutputCache Duration="15" VaryByParam="None" %>

把这个指令放在页面指令下。这告诉环境需要缓存页面,持续 15 秒。以下页面加载事件处理程序将帮助确认页面是否已被缓存完毕。

protected void Page_Load(object sender, EventArgs e)
{Thread.Sleep(10000);  Response.Write("This page was generated and cache at:" +DateTime.Now.ToString());
}

Thread.Sleep()方法使特定时间内的进程停止。在这个例子中,线程停止了 10 秒钟,因此,当页面第一次下载时,需要花费 10 秒钟的时间。然而,下次刷新页面的时候,就不会花费时间了,因为这个页面已经从缓存中获取了,不要再下载。

当帮助控制输出缓存的行为 OutputCache 指令有以下特性:

属性 描述
DiskCacheable true/false 描述输出是否可以写入带有缓存的磁盘。
NoStore true/false 描述 "no store" 缓存头部是否被发送。
CacheProfile 字符串名 存储在 web.config 中的缓存配置文件名字。
VaryByParam None
*
参数名
GET 请求中使用分号分隔的字符串值或者是 POST 请求中的变量值。
VaryByHeader *
头文件名
可能是由客户端提交的用分号分隔的指定头的字符串。
VaryByCustom 浏览器
自定义字符串
通知 ASP.NET 通过浏览器名字版本或者客户端字符串改变输出缓存。
Location 任何
客户端
下载流
服务器
None
任何:页面可能缓存在任何位置
客户端:缓存内容包含在浏览器中
下载流:缓存内容保存在下载流和服务器中
服务器:缓存仅保存在服务器之中
None:不允许缓存。
Duration 数字 被缓存页面或者操作的秒数。

让我们为前面的示例添加一个文本框和一个按钮,并添加这个按钮的事件处理程序。

protected void btnmagic_Click(object sender, EventArgs e)
{Response.Write("<br><br>");Response.Write("<h2> Hello, " + this.txtname.Text + "</h2>");
}

改变 OutputCache 指令:

<%@ OutputCache Duration="60" VaryByParam="txtname" %>

程序执行的时候,ASP 在文本框中依据名字缓存页面。

数据缓存

数据缓存的主要方面是数据源控件缓存。我们已经讨论了数据源控件代表一个数据源中的数据,如数据库或 XML 文件。这些控件从抽象类 DataSourceControl 中派生,并有以下继承属性以实现缓存:

  • 缓存期 — 为缓存数据的数据源计时。
  • 缓存期满策略 — 定义了当数据在缓存中过期时,缓存的行为。
  • 缓存值依赖 — 定义了一个控件值,这个控件可以在数据期满时自动将其移出缓存。
  • 启用缓存 — 可以确认是否缓存了数据。

实例

为了演示数据缓存,我们创建一个新的网站,在上面添加一个新的网络表单。在数据库中添加一个连接数据访问教程的 SqlDataSource 控件。

在这个实例中,我们给页面添加一个标签,这个标签可以显示页面的回应时间。

<asp:Label ID="lbltime" runat="server"></asp:Label>

除了这个标签,整个页面和数据访问教程是一样的。为这个页面添加一个事件处理器,来下载时间。

protected void Page_Load(object sender, EventArgs e)
{lbltime.Text = String.Format("Page posted at: {0}", DateTime.Now.ToLongTimeString());
}

设计的页面应该是如下这个样子的:

当你第一次执行页面时,并没有发生什么不同。标签显示,每次刷新页面,页面会重新加载,而且在标签上会显示时间的变化。

接下来,把数据源控件的 EnableCaching 的属性设置为“真”,将 Cacheduration 属性设置为 “60”。它将实现缓存,缓存将每隔 60 秒到期。

每一次刷新,时间戳都会变化。但如果你在 60 秒之内改变表中的数据,在缓存到期之前将不会显示。

<asp:SqlDataSource ID = "SqlDataSource1" runat = "server" ConnectionString = "<%$ ConnectionStrings: ASPDotNetStepByStepConnectionString %>" ProviderName = "<%$ ConnectionStrings: ASPDotNetStepByStepConnectionString.ProviderName %>" SelectCommand = "SELECT * FROM [DotNetReferences]"EnableCaching = "true" CacheDuration = "60">
</asp:SqlDataSource>

对象缓存

对象缓存比其他缓存技术提供了更大的灵活性。你可以利用对象缓存在缓存中放置任何对象。对象也可以是任意类型的 — 数据类型,网络控件,类,数据设置对象等等。仅仅需要给这些项目分配一个值名,它们就可以被添加到缓存中,就像下面展示的这样:

Cache["key"] = item;

为了在缓存中插入对象, ASP 提供了 Insert() 方法。这种方法有四种重载版本。我们来看一下:

重载 描述
Cache.Insert((key, value); 以键值对的方式插入缓存,优先权和生命周期为默认 。
Cache.Insert(key, value, dependencies); 以键值对的方式插入缓存,优先权和生命周期为默认,和链接到其他文件或内容的缓存依赖,这样缓存修改就不再还有限的了。
Cache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration); 指出上述配置的有效期。
Cache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback); 与配置一起也允许设置缓存内容的优先权并委派,指出一种方法来调用当一个对象移除时。

动态生命周期使用于移除一个不作用于任何一个指定的时间跨度的缓存项。下面代码段用来保存一个具有 10 分钟滑动生命周期的无依赖的缓存项:

Cache.Insert("my_item", obj, null, DateTime.MaxValue, TimeSpan.FromMinutes(10));

实例

仅仅使用一个按钮和一个标签创建一个页面。在页面加载事件中写入如下代码:

protected void Page_Load(object sender, EventArgs e)
{if (this.IsPostBack){lblinfo.Text += "Page Posted Back.<br/>";}else{lblinfo.Text += "page Created.<br/>";}if (Cache["testitem"] == null){lblinfo.Text += "Creating test item.<br/>";DateTime testItem = DateTime.Now;lblinfo.Text += "Storing test item in cache ";lblinfo.Text += "for 30 seconds.<br/>";Cache.Insert("testitem", testItem, null, DateTime.Now.AddSeconds(30), TimeSpan.Zero);}else{lblinfo.Text += "Retrieving test item.<br/>";DateTime testItem = (DateTime)Cache["testitem"];lblinfo.Text += "Test item is: " + testItem.ToString();lblinfo.Text += "<br/>";}lblinfo.Text += "<br/>";
}

当页面第一次加载时,会显示:

Page Created.
Creating test item.
Storing test item in cache for 30 seconds.

如果你在 30 秒钟内再次点击按钮,虽然页面被删除了,但是标签控件会从缓存中得到信息,如下所示:

Page Posted Back.
Retrieving test item.
Test item is: 14-07-2010 01:25:04

ASP.NET 多线程

多线程

一个线程被定义为一个程序的执行路径。每个线程都定义了一个独特的流量控制。如果你的应用程序涉及到复杂的和耗时的操作,如数据库访问或一些激烈的 I/O 操作,那么往往设置不同的执行路径或线程,每个线程执行一个特定的工作是非常有益的。

线程是轻量级的进程。使用线程的一个常见的例子是现代操作系统并行编程的的实现。使用线程节省了 CPU 周期的损失,提高了应用效率。

到目前为止我们编译好的程序在一个线程作为一个单一的过程运行,即是应用程序的运行实例。然而,这样的应用程序只可以在某一时刻执行一个工作。让它在同一时间执行多个任务,可以把它分成更小的线程。

在 .Net ,线程是通过 ‘System.Threading’ 的命名空间处理的。创造的 system.threading.thread 类型的变量允许你创建一个新线程开始工作。它允许你在一个单独的线程创建和访问独立的线程。

创建线程

一个线程是由一个线程对象创建的,并给出了它的构造函数的开启线程的参考。

    ThreadStart childthreat = new ThreadStart(childthreadcall);

线程生命周期

一个线程的生命周期开始于 system.threading.thread 类的一个对象被创建,结束于线程被终止或执行完成。

以下是在一个线程的生命周期的各种状态:

  • 待开启状态:该线程的实例被创建但启动方法还未被调用的情况。
  • 就绪状态: 当线程准备好执行并且在等待 CPU 周期的情况。
  • 不可运行状态:线程不能被运行的情况,有以下几种可能:
    • 当前睡眠的方法被调用
    • 等待的方法被调用
    • 被 I/O 操作阻塞
  • 死亡状态:线程执行完毕或已中止的情况。

线程优先权

Thread 类中的优先级属性主要是相对于其他线程指定一个线程的优先级。 .NET 运行时选择具有最高优先级的就绪线程。优先权可分为:

  • 高于正常
  • 低于正常
  • 最高
  • 最低
  • 正常

一旦一个线程被创建,系统就会使用 Thread 类的优先级设置系统设定好它的优先级。

    NewThread.Priority = ThreadPriority.Highest;

线程的属性和方法

线程类具有以下重要特性:

属性 描述
CurrentContext 获取当前正在执行的线程的内容。
CurrentCulture 获取或设置当前线程的环境。
CurrentPrinciple 获取或设置当前进程关于基于角色的安全机制的原则。
CurrentThread 获取当前正在运行的线程。
CurrentUICulture 获取或设置当前运行的进程的资源管理器用于查找特定资源的当前环境。
ExecutionContext 获取包含有关当前线程的上下文信息的 ExecutionContext 对象。
IsAlive 获取一个值,指示当前线程的执行状态。
IsBackground 后台获取或设置一个值指示线程是否是后台线程。
IsThreadPoolThread 获取一个值,指示线程是否属于托管线程池。
ManagedThreadId 获取托管线程的当前唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,表示一个线程的调度优先级。
ThreadState 获取一个值,包含当前线程的状态。

线程类具有以下重要方法:

方法 描述
Abort 调用一个 ThreadAbortException 开始终止线程的过程,调用此方法通常会终止线程。
AllocateDataSlot 向所有线程分配一个未命名的数据槽。为了获得更好的性能,使用标有 ThreadStaticAttribute 属性的域。
AllocateNamedDataSlot 向所有线程上分配已命名的数据槽。为了获得更好的性能,使用的是标有 ThreadStaticAttribute 属性的域。
BeginCriticalRegion 通知宿主执行即将进入代码区域,那里线程中止或未处理的异常的影响可能危及其他任务的应用领域。
BeginThreadAffinity 通知主机托管代码将要执行,取决于当前的物理操作系统线程的标识说明。
EndCriticalRegion 通知宿主执行即将进入代码区域,那里线程中止或未处理的异常仅影响当前任务。
EndThreadAffinity 通知宿主托管代码执行完成,取决于当前的物理操作系统线程的标识说明。
FreeNamedDataSlot 为进程中的所有线程消除名称与槽之间的关联,为了获得更好的性能,使用的是标有 ThreadStaticAttribute 属性的域。
GetData 在当前线程的当前域从当前线程指定的插槽检索值。为了获得更好的性能,使用的是标有 ThreadStaticAttribute 属性的域。
GetDomain 返回当前域中当前正在执行的线程。
GetDomainID 返回唯一的应用程序域标识符。
GetNamedDataSlot 查找已命名的数据槽。为了获得更好的性能,使用的是标有 ThreadStaticAttribute 属性的域。
Interrupt 中断一个在 WaitSleepJoin 线程状态的线程。
Join 阻塞调用线程,直到某个线程终止,同时继续执行标准的 COM 和 SendMessage 。该方法具有不同的重载形式。
MemoryBarrier 同步内存访问如下:处理当前线程的加速器不能以存储器访问调用 MemoryBarrier 后先调用内存访问执行这种方式对指令重新排序。
ResetAbort 取消当前线程的中止请求。
SetData 设置数据在指定的时隙上当前运行的线程,该线程的当前域。为了获得更好的性能,应用领域有 ThreadStaticAttribute 属性的域。
Start 启动一个线程。
Sleep 使线程暂停一个时间段。
SpinWait 使线程等待的参数定义的迭代次数。
VolatileRead() 读取字段的值。最新的值是由计算机的任何处理器写入,不论处理器或处理器缓存的状态数。该方法具有不同的重载形式。
VolatileWrite() 立即向字段写入一个值,这样的值是对计算机中的所有处理器可见。该方法具有不同的重载形式。
Yield 使调用线程执行可以在当前的处理器运行的另一个线程,操作系统选用转向的县城

例子

下面的例子阐明了对线程类的使用。该页面有一个控制标签显示子线程传来的消息。从主程序传来的消息直接使用 response.write(50) 的方法显示出来,因此它们出现在页面的顶部。

源文件如下:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="threaddemo._Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"><title>Untitled Page</title></head><body><form id="form1" runat="server"><div><h3>Thread Example</h3></div><asp:Label ID="lblmessage" runat="server" Text="Label"></asp:Label></form></body></html>

后台代码如下:

    using System;using System.Collections;using System.Configuration;using System.Data;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using System.Threading;namespace threaddemo{public partial class _Default : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){ThreadStart childthreat = new ThreadStart(childthreadcall);Response.Write("Child Thread Started <br/>");Thread child = new Thread(childthreat);child.Start();Response.Write("Main sleeping  for 2 seconds.......<br/>");Thread.Sleep(2000);Response.Write("<br/>Main aborting child thread<br/>");child.Abort();}public void childthreadcall(){try{lblmessage.Text = "<br />Child thread started <br/>";lblmessage.Text += "Child Thread: Coiunting to 10";for( int i =0; i<10; i++){Thread.Sleep(500);lblmessage.Text += "<br/> in Child thread </br>";}lblmessage.Text += "<br/> child thread finished";}catch(ThreadAbortException e){lblmessage.Text += "<br /> child thread - exception";}finally{lblmessage.Text += "<br /> child thread - unable to catch the  exception";}}}}

观察以下:

  • 当页面被加载时,一个新的线程会以 childthreadcall() 为参考开始启动。主线程的活动会直接显示在网页。
  • 第二个线程运行并将消息发送到控制标签。
  • 在子线程执行时主线程休眠 2000 毫秒。
  • 子线程持续运行直到它被主线程中止,然后它会抛出 ThreadAbortException 异常并被终止。
  • 控制返回到主线程。
  • 当执行时程序会发送以下信息:

github:  https://github.com/ixixii/ASP.NET_03_WebForms

未完待续,下一章节,つづく

ASP.NET 系列_07_编程指南(三)相关推荐

  1. ASP.NET 系列_08_编程指南(四)

    ASP.NET 安全性 安全性 实现网站的安全性关系到如下几方面: 身份认证:即确认用户身份和真实性的过程.ASP.NET 中提供了四种类型的认证: Windows 认证 表单认证 身份验证 自定义认 ...

  2. CoreAnimation编程指南(三)几何变换

    本章介绍图层的几何组成部分,及他们之间的相互关,同时介绍如何变换矩阵可以产生复杂的视觉效果. 一.图层的坐标系 1.图层的坐标系在不同平台上面具有差异性.在iOS系统中,默认的坐标系统原点在图层的中心 ...

  3. ios跨线程通知_iOS多线程编程指南(三)Run Loop

    Run loops是线程相关的的基础框架的一部分.一个run loop就是一个事件处理的循环,用来不停的调度工作以及处理输入事件.使用run loop的目的是让你的线程在有工作的时候忙于工作,而没工作 ...

  4. libuv 中文编程指南(零)前言

    最近看了一些有关 libuv 的东西,另外复习了一些与同步.异步.阻塞.非阻塞,异步IO(aio)的东西, 算是技术积累吧,等有时间了整理出一个完整的文档出来,希望在今后的编程中用到. 不多说了,本文 ...

  5. libuv 中文编程指南

    最近看了一些有关 libuv 的东西,另外复习了一些与同步.异步.阻塞.非阻塞,异步IO(aio)的东西, 算是技术积累吧,等有时间了整理出一个完整的文档出来,希望在今后的编程中用到. 不多说了,本文 ...

  6. 高质量C++/C编程指南 1

    高质量C++/C编程指南 文件状态 [ ] 草稿文件 [√] 正式文件 [ ] 更改正式文件 文件标识: 当前版本: 1.0 作 者: 林锐 博士 完成日期: 2001年7月24日 http://ma ...

  7. 学习ASP.NET Core Razor 编程系列三——创建数据表及创建项目基本页面

    原文:学习ASP.NET Core Razor 编程系列三--创建数据表及创建项目基本页面 学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 ...

  8. 学习ASP.NET Core Razor 编程系列九——增加查询功能

    原文:学习ASP.NET Core Razor 编程系列九--增加查询功能 学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.N ...

  9. 2011年3月华章新书书讯:ASP.NET本质论、Erlang编程指南、SNS网站构建

    ASP.NET本质论 深入剖析ASP.NET的运行机制和工作原理,带你领略ASP.NET的本质和精髓 包含大量开发技巧和最佳实践,为开发稳定而高效的ASP.NET应用提供绝佳指导 SNS网站构建 提供 ...

最新文章

  1. 常见设计模式,单例模式(双重检测锁方式)示例
  2. Linux套接字聊天
  3. python k-means聚类分析_python进行数据分析
  4. 滑坡泥石流的防御措施_滑坡泥石流防御
  5. 教育部推出首批490门“国家精品在线开放课程”
  6. java todo error_Java全局异常处理(TODO)
  7. css3实现 依次出现三个点(一般用于提示加载中。。。 提交中。。。)
  8. 最新版 | 李沐《动手学深度学习》中文版pdf重磅开源!
  9. 今天开始写一些内容,留作备份。
  10. MySQL服务无法正常启动的解决方法(1053错误)
  11. NLP︱高级词向量表达(二)——FastText(简述、学习笔记)
  12. 一文了解机器学习以及其相关领域(上)
  13. Spring自学教程-AOP学习(五)
  14. Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute
  15. SAP WM + PDA项目 来料入库流程
  16. 正则判断手机号地区_手机号码验证方法(正则验证)
  17. MapReduce: Simplified Data Processing on Large Clusters 翻译和理解
  18. OpenGL 之 EGL 使用实践
  19. Android Studio打不开,出现start failed的报错
  20. vivo android8公测,vivo安卓9.0公测招募开启:明年年初获得推送

热门文章

  1. 使用化境无组件上传遇到的问题
  2. YYC松鼠视频pro版安装实操001
  3. 树莓派Linu内核编译
  4. cron表达式 指定日期后面每天运行
  5. SFP、SFP+、SFP28、QSFP+和QSFP28之间的区别
  6. Sonarqube的搭建和使用入门
  7. educoder数据结构与算法 线性表 第2关:实现一个链接存储的线性表
  8. 众号运营必备的10款工具
  9. LCD显示屏和LED显示屏的区别,LCD液晶屏与LED显示屏什么区别
  10. aws 认证_如何在家工作时获得任何AWS认证