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 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 视图是 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 控件代表到相关数据库比如 SQL Server 或者 Oracle数据库,或者通过 OLEDB 或 Open Database Connectivity(ODBC) 的可存取数据的连接。数据连接通过两个重要的属性 ConnectionString 和 ProviderName 完成。
以下的代码片段提供了控件的基本语法:
在潜在的数据上配置不同的数据操作依赖于 data source 控件的不同属性(属性集)。
以下的表格提供了相关的 SqlDataSource 控件的属性集,它提供了控件的编程接口:
属性组 | 描述 |
---|---|
DeleteCommand, DeleteParameters, DeleteCommandType |
获取或设置 SQL 语句,参数和在潜在数据中删除行的类型。 |
FilterExpression, FilterParameters |
获取并设置数据过滤字符串和参数。 |
InsertCommand, InsertParameters, InsertCommandType |
获取或设置 SQL 语句,参数和在潜在数据中插入行的类型。 |
SelectCommand, SelectParameters, SelectCommandType |
获取或设置 SQL 语句,参数和在潜在数据中检索行的类型。 |
SortParameterName | 获取或设置一个输入参数的名字,它将被命令存储的过程用来给数据排序。 |
UpdateCommand, UpdateParameters, UpdateCommandType |
获取或设置 SQL 语句,参数和在潜在数据中更新行的类型。 |
以下的代码片段展示了能被用来做数据操作的 data source 控件:
.....
.....
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 对象和检索数据:
AccessDataSource 控件代表了到 Access 数据库的连接。它基于 SqlDataSource 控件并提供了更简单的编程接口。以下的代码片段提供了 data source 的基本语法:
AccessDataSource 控件打开了只读模式的数据库。但是,它也能被用来执行插入,更新或者删除操作。这以使用 ADO.NET 命令和参数集合来完成。
更新对于 ASP.NET 应用程序内的 Access 数据库来说是有问题的,这是因为 Access 数据库是一个纯文本并且默认的 ASP.NET 应用程序账户可能有写数据库文件的权限。
ASP.NET 允许存取和使用下列数据源:
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" %>
Untitled Page
每一个 ASP.NET 网页表单控件从它的父控件类继承了 DataBind 方法,它给予了它继承的能力来绑定数据到它属性中的至少一个属性。这就是所谓的简单数据绑定或者内部数据绑定。
简单数据绑定包括将任何实现 IEnumerable 接口的集合(项目集合),或者 DataSet 和 DataTable 类附加到控件的 DataSource 属性。
另一方面,一些控件可以通过 DataSource 控件绑定记录,列表,或者数据列到它们的结构中。这些控件源自 BaseDataBoundControl 类。这被叫做描述性数据绑定。
data source 控件帮助 data-bound 控件实现了比如排序,分页和编辑数据集合的功能。
BaseDataBoundControl 是一个抽象类,它通过两个抽象类继承:
抽象类 DataBoundControl 也由两个抽象类继承:
能够简单绑定数据的控件源自 ListControl 抽象类并且这些控件是:
能够描述性数据绑定的控件(一个更复杂的数据绑定)源自抽象类 CompositeDataBoundControl。这是控件是:
简单数据绑定包括只读选择列表。这些控件能绑定一个数组列或者数据库的字段。选择列表从数据库中或 data source 中取两个值;一个值用过列表表示而另一个被认为是相应显示的值。
让我们使用一个小例子来理解这个概念。用一个项目符号列表和一个 SqlDataSource 控件来创建一个网页。配置 data source 控件来从你的数据库中(我们在之前的章节中使用相同的 DotNetReferences 表)检索两个值。
为包含的项目符号列表控件选择一个 data source:
当应用程序执行的时候,检查整个标题列绑定到项目符号列表并被展示。
我们已经在之前的指南中使用 GridView 控件来使用描述性数据绑定。其他复合的能够以表格的方式展示并操作数据的 data bound 控件是 DetailsView, FormView 和 RecordList 控件。
在下一个指南中,我们将研究解决数据库,i.e,ADO.NET 的 技术。
但是,数据绑定包括以下对象:
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 和四个与这些列表控件一起的四个表单。在设计视图中页面应该看起来像这样:
源文件应该看起来像下面这样:
步骤(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;
}
}
观察以下:
ASP.NET 允许用户创建控件。这些用户定义的控件被分类为:
用户控件行为像微型 ASP.NET 页面或者网页表单,它能被许多其他页面使用。这些都是源自 System.Web.UI.UserControl 类。这些控件有下列特性:
为了理解这个概念,让我们创建一个简单的用户控件,它将作为 web 页面的页脚使用。为了创建和使用用户控件,采取以下步骤:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="footer.ascx.cs"
Inherits="customcontroldemo.footer" %>
Copyright ©2010 TutorialPoints Ltd.
Location: Hyderabad, A.P
为给你的 web 网页添加用户控件,你必须添加 Register 指令和一个页面用户控件的实例。以下的代码展示了说明:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="customcontroldemo._Default" %>
<%@ Register Src="~/footer.ascx" TagName="footer" TagPrefix="Tfooter" %>
Untitled Page
当执行后,页面显示了页脚而且这个控件能在所有你的网站的页面中被使用。
观察以下:
(1)Register 指令为控件指定了一个标签名称和标签前缀。
<%@ Register Src="~/footer.ascx" TagName="footer" TagPrefix="Tfooter" %>
(2)下列的标签名称和前缀应该在页面上添加用户控件时被使用:
自定义控件被部署为单独的集合。它们被编译成动态链接库(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" %>
而且,你可以使用控件,和任何其他控件类似。
当执行后,控件的 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>")]
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>")]
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:
");
output.Write("");
output.Write("");
output.Write(Text);
output.Write("");
output.Write("");
}
else
{
output.Write("This is not a palindrome:
");
output.Write("");
output.Write("");
output.Write(Text);
output.Write("");
output.Write("");
}
}
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。
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 个性化服务基于用户的特征文件。用户特征文件定义了该网站需要用户的信息。例如,名字,年龄,地址,出生日期和手机号码。
这个信息被定义在应用程序的 web.config 文件中并且 ASP.NET 运行时间阅读并使用它。这个工作由个性化提供者所完成。
用户数据所含有的用户特征文件被存储在默认的 ASP.NET 创建的数据库中。你可以创建你自己的数据库来存储特征文件。特征文件数据定义被存储在配置文件 web.config 中。
让我们创建一个样本网站,那里我们想要我们的应用程序记住用户细节,像名字,地址,出生日期等。在 web.config 文件中用 元素添加特征文件细节。
当特征文件在 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 文件可以被配置成以下:
在 ASP.NET 中异常处理有三个方面:
在这一章中,我们将讨论 tracing 和 handling。
并且在这一章中,我们将涉及 debugging。
为了理解概念,创建以下的样本应用程序。它有一个 label 控件,一个 dropdown 列表和一个链接。dropdown 列表加载了一个名言的 array 列表并且被选择的引用将显示在下面的标签中。它也拥有一个超链接,它指向一个不存在的链接。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="errorhandling._Default" %>
Tracing, debugging and error handling
文件后的代码:
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
为了允许页面级别的追踪,你需要修改 Page 指令并且如下添加一个 Trace 属性:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="errorhandling._Default" Trace ="true" %>
现在当你执行文件时,你将得到追踪信息:
它在首部提供了以下的信息:
每次页面被需要时,从服务器发出的 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 文件被实现:
尽管 ASP.NET 能检测所有的运行时错误,仍然有一些微小的错误仍在那儿。通过追踪观察错误是为开发者准备的,而不是用户。
因此,为了拦截这样情况的发生,你可以在应用程序的 web.config 中添加错误解决设置。它是应用程序范围的错误解决。例如,你可以在 web.config 文件中添加以下的代码:
部分有可能的属性: - **Mode:**它允许或者不允许自定义错误页面。它有三个可能的值: - **On:**展示自定义页面。 - **Off:**展示 ASP.NET 错误页面(黄色页面) - **remoteOnly:**它展示了自定义错误到客户端,展示本地的 ASP.NET 错误。- **defaultRedirect:**它含有页面的 URL 来展示以备不能解决的错误。 为了给不同错误类型放置不同的自定义错误页面,子标签被使用,那里不同的错误页面基于错误的 status 代码被指定。 为了实现页面级别的错误解决,Page 指令能被修改为: `````` 因为 ASP.NET Debugging 是它内部一个重要的主题,因此我们将在下一章单独地讨论它。
Debugging 可以让开发人员一步一步的看到代码是怎样工作的,变量的值是如何变化的和对象是怎样被创建又是怎样被销毁的等等。
当一个网页第一次被运行时,Visual Studio 会弹出一个提示框来询问 Debugging 是否需要被启用:
当 debugging 被启用时,下面几行代码将在 web.config 文件中出现:
..............
Debugging 工具栏会提供所有 debugging 所需的工具:
断点规定程序在运行时在运行完指定的代码行之后立即停止运行,这样可以测试代码并且完成各种各样的 debugging 工作,例如,观察变量值的变化,单步调试代码,函数方法的跳入跳出等。
在代码上单击右键选择插入一个间断点来设置断点。然后在左边会出现一个红点并且该行代码被高亮显示,效果如图所示:
之后你运行这段代码,将会观察到断点的行为。
在这个阶段,你可以单步调试代码,观察运行的流程和变量值、属性、对象等。
如果你需要修改断点属性,你可以在断点标志上单击右键,在“属性”菜单中找到:
location 对话框显示文件所在位置,以及所选中的代码所在行数和字符数。condition 菜单允许你输入一个有效的表达式来估算程序是否运行到了断点:
Hit Count 菜单显示一个对话框来显示断点被运行的次数。
点击下拉菜单中的任何一个选项会打开一个用来输入命中次数的编辑框。这在分析循环结构的代码时非常有用。
Filter 菜单允许设置一个对特定机制、过程、线程或是任何组合的过滤使断点对它们生效。
When Hit 菜单允许你来指定当断点命中时的动作。
Visual Studio 提供下面的 debug 窗口,其中每一个都显示一些程序信息。下表列出了一些窗口:
窗口 | 描述 |
---|---|
直接 | 显示变量和表达式。 |
自动 | 显示当前所有变量以及之前的状态。 |
本地 | 显示当前上下文的所有变量。 |
观察 | 显示多达四个不同集合的变量。 |
调用栈 | 显示调用栈中的所有方法。 |
线程 | 显示并控制线程。 |
大多数应用都是以数据为中心的,然而大多数的数据仓库是关系型数据库。这些年,设计者和开发者设计了基于对象模型的应用程序。
对象来负责连接访问数据的组件——称为数据访问层( DAL )。这里我们需要考虑三点:
因此如果存在只是用几行代码就能实现轻易整合各种各样的数据——可以整合来自不同源的数据,并且能够执行基本的数据操作的工具,那将非常有用。
语言集成查询( 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;
其中:
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 GetBooks()
{
List list = new List();
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.GetBooks();
var booktitles = from b in books select b.Title;
foreach (var title in booktitles)
lblbooks.Text += String.Format("{0}
", title);
}
}
当网页被运行,标签显示查询结果:
上面的 LINQ 表达式:
var booktitles =
from b in books
select b.Title;
等价于下述 SQL 语句:
SELECT Title from Books
除了到目前为止使用过的运算符之外,还有很多其他运算符来执行查询子句。我们来看一些运算符和子句。
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 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();
}
}
在 Page_Load 函数中添加代码来用 join 子句处理在两张表里完成查询:
protected void Page_Load(object sender, EventArgs e)
{
IEnumerable books = Books.GetBooks();
IEnumerable sales = Salesdetails.getsalesdetails();
var booktitles = from b in books join s in sales on b.ID equals s.ID
select new { Name = b.Title, Pages = s.pages };
foreach (var title in booktitles)
lblbooks.Text += String.Format("{0}
", title);
}
结果页显示如下:
where 子句允许在查询中添加筛选条件。例如,如果你想获得页数多于 500 的书目,可以改变 Page_Load 方法中的句柄成下述样子:
var booktitles = from b in books join s in sales on b.ID equals s.ID
where 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.ID
orderby b.Price select new { Name = b.Title, Pages = s.pages, Price = b.Price};
返回的元组是:
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.ID
let totalprofit = (b.Price * s.sales)
select new { Name = b.Title, TotalSale = totalprofit};
查询结果如下图所示:
缓存是一种将经常使用的数据/信息存储在内存中的技术,这样,下次需要相同的数据/信息时,可以直接从内存检索,而不是再从应用程序中生成。
缓存在用于提高 ASP 性能方面是非常重要的,因为 ASP 的页面和控件是都动态生成的。这对于交互相关的数据是极其重要的,因为响应时间是很宝贵的。
在需要快速访问的媒体,如计算机的随机存取存储器,缓存放置了被频繁使用的数据。ASP 的运行时间包含一个叫做缓存的 CLR 对象的键值对。它位于应用程序内,并且通过 HttpContext 和 System.Web.UI.Page 可用。
在某些方面,缓存和存储状态对象有相似之处。然而,状态对象的存储信息是确定的,比如,你可以计算存储在状态对象的数据,但是缓存的数据是不确定的。
在下列情况里,数据是不可用的:
您可以使用一个索引器在缓存中访问项目,并且有可能控制缓存中对象的生命周期和设置缓存的对象及其物理资源之间的联系。
ASP提供如下几种不同类型的缓存:
在本教程中,我们将考虑输出缓存,数据缓存和对象缓存。
呈现一个页面可能涉及一些复杂的过程,如,数据库访问,呈现复杂的控件等。输出缓存允许通过在内存中缓存数据,而绕过往返服务器。甚至可以缓存整个页面。
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("
");
Response.Write(" Hello, " + this.txtname.Text + "
");
}
改变 OutputCache 指令:
<%@ OutputCache Duration="60" VaryByParam="txtname" %>
程序执行的时候,ASP 在文本框中依据名字缓存页面。
数据缓存的主要方面是数据源控件缓存。我们已经讨论了数据源控件代表一个数据源中的数据,如数据库或 XML 文件。这些控件从抽象类 DataSourceControl 中派生,并有以下继承属性以实现缓存:
为了演示数据缓存,我们创建一个新的网站,在上面添加一个新的网络表单。在数据库中添加一个连接数据访问教程的 SqlDataSource 控件。
在这个实例中,我们给页面添加一个标签,这个标签可以显示页面的回应时间。
除了这个标签,整个页面和数据访问教程是一样的。为这个页面添加一个事件处理器,来下载时间。
protected void Page_Load(object sender, EventArgs e)
{
lbltime.Text = String.Format("Page posted at: {0}", DateTime.Now.ToLongTimeString());
}
设计的页面应该是如下这个样子的:
当你第一次执行页面时,并没有发生什么不同。标签显示,每次刷新页面,页面会重新加载,而且在标签上会显示时间的变化。
接下来,把数据源控件的 EnableCaching 的属性设置为“真”,将 Cacheduration 属性设置为 “60”。它将实现缓存,缓存将每隔 60 秒到期。
每一次刷新,时间戳都会变化。但如果你在 60 秒之内改变表中的数据,在缓存到期之前将不会显示。
对象缓存比其他缓存技术提供了更大的灵活性。你可以利用对象缓存在缓存中放置任何对象。对象也可以是任意类型的 — 数据类型,网络控件,类,数据设置对象等等。仅仅需要给这些项目分配一个值名,它们就可以被添加到缓存中,就像下面展示的这样:
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.
";
}
else
{
lblinfo.Text += "page Created.
";
}
if (Cache["testitem"] == null)
{
lblinfo.Text += "Creating test item.
";
DateTime testItem = DateTime.Now;
lblinfo.Text += "Storing test item in cache ";
lblinfo.Text += "for 30 seconds.
";
Cache.Insert("testitem", testItem, null,
DateTime.Now.AddSeconds(30), TimeSpan.Zero);
}
else
{
lblinfo.Text += "Retrieving test item.
";
DateTime testItem = (DateTime)Cache["testitem"];
lblinfo.Text += "Test item is: " + testItem.ToString();
lblinfo.Text += "
";
}
lblinfo.Text += "
";
}
当页面第一次加载时,会显示:
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
一个线程被定义为一个程序的执行路径。每个线程都定义了一个独特的流量控制。如果你的应用程序涉及到复杂的和耗时的操作,如数据库访问或一些激烈的 I/O 操作,那么往往设置不同的执行路径或线程,每个线程执行一个特定的工作是非常有益的。
线程是轻量级的进程。使用线程的一个常见的例子是现代操作系统并行编程的的实现。使用线程节省了 CPU 周期的损失,提高了应用效率。
到目前为止我们编译好的程序在一个线程作为一个单一的过程运行,即是应用程序的运行实例。然而,这样的应用程序只可以在某一时刻执行一个工作。让它在同一时间执行多个任务,可以把它分成更小的线程。
在 .Net ,线程是通过 ‘System.Threading’ 的命名空间处理的。创造的 system.threading.thread 类型的变量允许你创建一个新线程开始工作。它允许你在一个单独的线程创建和访问独立的线程。
一个线程是由一个线程对象创建的,并给出了它的构造函数的开启线程的参考。
ThreadStart childthreat = new ThreadStart(childthreadcall);
一个线程的生命周期开始于 system.threading.thread 类的一个对象被创建,结束于线程被终止或执行完成。
以下是在一个线程的生命周期的各种状态:
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" %>
Untitled Page
后台代码如下:
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
");
Thread child = new Thread(childthreat);
child.Start();
Response.Write("Main sleeping for 2 seconds.......
");
Thread.Sleep(2000);
Response.Write("
Main aborting child thread
");
child.Abort();
}
public void childthreadcall()
{
try{
lblmessage.Text = "
Child thread started
";
lblmessage.Text += "Child Thread: Coiunting to 10";
for( int i =0; i<10; i++)
{
Thread.Sleep(500);
lblmessage.Text += "
in Child thread ";
}
lblmessage.Text += "
child thread finished";
}catch(ThreadAbortException e){
lblmessage.Text += "
child thread - exception";
}finally{
lblmessage.Text += "
child thread - unable to catch the exception";
}
}
}
}
github: https://github.com/ixixii/ASP.NET_03_WebForms
未完待续,下一章节,つづく