异步页为由 I/O 绑定的请求引起的问题提供优秀的解决方案。页处理从线程池线程开始,但是当一个异步 I/O 操作开始响应 ASP.NET 的信号之后,该线程返回线程池。当该操作完成时,ASP.NET 从线程池提取另一个线程,并完成该请求的处理。由于线程池线程得到了更高效的使用,因此提高了可伸缩性。那些挂起等待 I/O 完成的线程现在可用于服务其他请求。直接的受益方是不执行长时间 I/O 操作并因此可以快速进出管线的请求。长时间等待进入管线会对此类请求的性能带来不小的负面影响。
1 在aspx页面中的@Page指令引入Async="true"属性。
例如:
<%@ Page Language="C#" AutoEventWireup="true" Async="true" MasterPageFile="~/Site.master" CodeFile="AsyncPage.aspx.cs" Inherits="AsyncPage" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="Title">
Asynchronous Pages
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Descript" runat="server">
This Page demonstrates how to use Page.AddOnPreRenderComplete to perform asynchronous
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Main" runat="server">
<asp:Label ID="OutPut" runat="server"></asp:Label>
</asp:Content>
2 在后台cs文件中实现 IhttpAsyncHandler。接下来,您在该页生存期的早期(例如,在 Page_Load 时)调用新的 Page.AddOnPreRenderCompleteAsync 方法来注册一个 Begin 方法和一个 End 方法,如以下代码所示:
protected void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
}
接下来的操作比较有趣。该页经历其常规处理生命周期,直到 PreRender 事件刚刚引发之后。然后,ASP.NET 调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法。Begin 方法的任务是启动诸如数据库查询或 Web 服务调用的异步操作,并立即返回。此时,分配给该请求的线程返回到线程池。此外,Begin 方法返回 IAsyncResult,它允许 ASP.NET 确定异步操作完成的时间,这个时候 ASP.NET 从线程池提取线程并调用 End 方法。当 End 返回之后,ASP.NET 执行该页生命周期其余的部分,包括呈现阶段。在 Begin 返回以及调用 End 之间,该请求处理线程可以自由地服务于其他请求,直至调用 End 且延迟呈现为止。由于 2.0 版的 .NET Framework 提供多种执行异步操作的方式,因此,您甚至无需实现 IasyncResult。反之,Framework 替您实现。
1 在aspx页面中的@Page指令引入Async="true"属性。
例如:
<%@ Page Language="C#" AutoEventWireup="true" Async="true" MasterPageFile="~/Site.master" CodeFile="AsyncPage.aspx.cs" Inherits="AsyncPage" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="Title">
Asynchronous Pages
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Descript" runat="server">
This Page demonstrates how to use Page.AddOnPreRenderComplete to perform asynchronous
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Main" runat="server">
<asp:Label ID="OutPut" runat="server"></asp:Label>
</asp:Content>
2 在后台cs文件中实现 IhttpAsyncHandler。接下来,您在该页生存期的早期(例如,在 Page_Load 时)调用新的 Page.AddOnPreRenderCompleteAsync 方法来注册一个 Begin 方法和一个 End 方法,如以下代码所示:
protected void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
}
接下来的操作比较有趣。该页经历其常规处理生命周期,直到 PreRender 事件刚刚引发之后。然后,ASP.NET 调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法。Begin 方法的任务是启动诸如数据库查询或 Web 服务调用的异步操作,并立即返回。此时,分配给该请求的线程返回到线程池。此外,Begin 方法返回 IAsyncResult,它允许 ASP.NET 确定异步操作完成的时间,这个时候 ASP.NET 从线程池提取线程并调用 End 方法。当 End 返回之后,ASP.NET 执行该页生命周期其余的部分,包括呈现阶段。在 Begin 返回以及调用 End 之间,该请求处理线程可以自由地服务于其他请求,直至调用 End 且延迟呈现为止。由于 2.0 版的 .NET Framework 提供多种执行异步操作的方式,因此,您甚至无需实现 IasyncResult。反之,Framework 替您实现。
列子整体代码。响应页包含一个 ID 为“Output”的 Label 控件。该页使用 System.Net.HttpWebRequest 类提取MSDN的内容。然后,它分析返回的 HTML,并将它发现的全部 HREF 目标列表写出到 Label 控件。
前台aspx:
<%@ Page Language="C#" AutoEventWireup="true" Async="true" MasterPageFile="~/Site.master" CodeFile="AsyncPage.aspx.cs" Inherits="AsyncPage" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="Title">
Asynchronous Pages
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Descript" runat="server">
This Page demonstrates how to use Page.AddOnPreRenderComplete to perform asynchronous
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Main" runat="server">
<asp:Label ID="OutPut" runat="server"></asp:Label>
</asp:Content>
后台cs
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
前台aspx:
<%@ Page Language="C#" AutoEventWireup="true" Async="true" MasterPageFile="~/Site.master" CodeFile="AsyncPage.aspx.cs" Inherits="AsyncPage" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="Title">
Asynchronous Pages
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Descript" runat="server">
This Page demonstrates how to use Page.AddOnPreRenderComplete to perform asynchronous
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Main" runat="server">
<asp:Label ID="OutPut" runat="server"></asp:Label>
</asp:Content>
后台cs
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
//Asp.Net异步回调 请求页面处理
public partial class AsyncPage : System.Web.UI.Page
{
private WebRequest _request;
protected void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
}
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
}
public IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state)
{
_request = WebRequest.Create("http://www.sina.com.cn");
return _request.BeginGetResponse(cb, state);
}
{
_request = WebRequest.Create("http://www.sina.com.cn");
return _request.BeginGetResponse(cb, state);
}
void EndAsyncOperation(IAsyncResult ar)
{
string text;
using (WebResponse response = _request.EndGetResponse(ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
text = reader.ReadToEnd();
}
}
{
string text;
using (WebResponse response = _request.EndGetResponse(ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
text = reader.ReadToEnd();
}
}
Regex regex = new Regex("href\\s*=\\s*\"([^\"]*)\"",RegexOptions.IgnoreCase);
MatchCollection matches = regex.Matches(text);
StringBuilder builder = new StringBuilder(1024);
foreach (Match match in matches)
{
builder.Append(match.Groups[1]);
builder.Append("<br/>");
}
{
builder.Append(match.Groups[1]);
builder.Append("<br/>");
}
OutPut.Text = builder.ToString();
}
}
}
}