asp.net异步调用

直接看代码吧:

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;
using System.Net;
using System.IO;
using System.Data.SqlClient;
public partial class _Default : System.Web.UI.Page 
{
    
private WebRequest _request;
    
protected void Page_Load(object sender, EventArgs e)
    
{
        
if (!IsPostBack)
        
{
             
this.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
            AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation), new EndEventHandler(EndAsycOperation));

        }

             
    }


    IAsyncResult BeginAsyncOperation(
object sender, EventArgs e, AsyncCallback cb, object state)
    
{
        _request 
= WebRequest.Create("http://msdn.microsoft.com");
        
return _request.BeginGetResponse(cb, state);
 
    }

    
void EndAsycOperation(IAsyncResult ar)
    
{
        
string text;
        
using (WebResponse response = _request.EndGetResponse(ar))
        
{
            
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            
{
                text 
= reader.ReadToEnd();
            }

        }

        
this.TextBox1.Text = text;

     }


 }



异步访问数据库的代码:
页面中要记得加上Async="true"指令,还有数据库连接字符串要设置Asynchronous Processing=True
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;
using System.Net;
using System.IO;
using System.Data.SqlClient;
public partial class _Default : System.Web.UI.Page 
{
     
private SqlConnection _connection;
    
private SqlCommand _command;
    
private SqlDataReader _reader;

    
protected void Page_Load(object sender, EventArgs e)
    
{
       
        
if (!IsPostBack)
        
{
             
this.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
            AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation), new EndEventHandler(EndAsycOperation));

        }

             
    }


    IAsyncResult BeginAsyncOperation(
object sender, EventArgs e, AsyncCallback cb, object state)
    
{

        
string sqlstr = "Server=localhost; Database=EEWM; User ID=sa; Password=KingSun;  Asynchronous Processing=true";
        _connection 
= new SqlConnection(sqlstr);
        _connection.Open();
        _command 
= new SqlCommand("select  * from INV_TRANSACTION", _connection);
        
return _command.BeginExecuteReader(cb, state);
        

    }

    
void EndAsycOperation(IAsyncResult ar)
    
{

        _reader 
= _command.EndExecuteReader(ar);

    }


    
public void Page_PreRenderComplete(object sender, EventArgs e)
    
{
          //这里有个很奇怪的问题,事件处理函数名如果是Page_PreRenderComplete,则GridView不能正确的显示填充结果,
         //换成其他名字,则能正确的显示...................................................
     
        this.GridView1.DataSource = (object)_reader;
        
this.GridView1.DataBind();
    }

    
public override void Dispose()
    
{
        
if (_connection != null) _connection.Close();
        
base.Dispose();
    }


}


以下代码为转载:
异步调用WebService
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class AsyncWSInvoke1 : System.Web.UI.Page
{
    
private WS.PubsWebService _ws;
    
private DataSet _ds;

    
protected void Page_Load(object sender, EventArgs e)
    
{
        
if (!IsPostBack)
        
{
            
// Hook PreRenderComplete event for data binding
            this.PreRenderComplete += 
                
new EventHandler(Page_PreRenderComplete);

            
// Register async methods
            AddOnPreRenderCompleteAsync(
                
new BeginEventHandler(BeginAsyncOperation),
                
new EndEventHandler(EndAsyncOperation)
            );
        }

    }


    IAsyncResult BeginAsyncOperation (
object sender, EventArgs e, 
        AsyncCallback cb, 
object state)
    
{
        _ws 
= new WS.PubsWebService();
        
// Fix up URL for call to local VWD-hosted Web service
        _ws.Url = new Uri(Request.Url, "Pubs.asmx").ToString();
        _ws.UseDefaultCredentials 
= true;
        
return _ws.BeginGetTitles (cb, state);
    }


    
void EndAsyncOperation(IAsyncResult ar)
    
{
        _ds 
= _ws.EndGetTitles(ar);
    }


    
protected void Page_PreRenderComplete(object sender, EventArgs e)
    
{
        Output.DataSource 
= _ds;
        Output.DataBind();
    }


    
public override void Dispose()
    
{
        
if (_ws != null) _ws.Dispose();
        
base.Dispose();
    }

}

换一种方式异步调用WebService
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class AsyncWSInvoke2 : System.Web.UI.Page
{
    
private WS.PubsWebService _ws;
    
private DataSet _ds;

    
protected void Page_Load(object sender, EventArgs e)
    
{
        
if (!IsPostBack)
        
{
            
// Hook PreRenderComplete event for data binding
            this.PreRenderComplete += 
                
new EventHandler(Page_PreRenderComplete);

            
// Call the Web service asynchronously
            _ws = new WS.PubsWebService();
            _ws.GetTitlesCompleted 
+= new 
                WS.GetTitlesCompletedEventHandler(GetTitlesCompleted);
            _ws.Url 
= new Uri(Request.Url, "Pubs.asmx").ToString();
            _ws.UseDefaultCredentials 
= true;
            _ws.GetTitlesAsync();
        }

    }


    
void GetTitlesCompleted(Object source, 
        WS.GetTitlesCompletedEventArgs e)
    
{
        _ds 
= e.Result;
    }


    
protected void Page_PreRenderComplete(object sender, EventArgs e)
    
{
        Output.DataSource 
= _ds;
        Output.DataBind();
    }


    
public override void Dispose()
    
{
        
if (_ws != null) _ws.Dispose();
        
base.Dispose();
    }

}

加TimeOut处理的异步调用:
Page标志加属性: Async="true" AsyncTimeout="5"
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

public partial class AsyncPageTask : System.Web.UI.Page
{
    
private WebRequest _request;

    
protected void Page_Load(object sender, EventArgs e)
    
{
        PageAsyncTask task 
= new PageAsyncTask(
            
new BeginEventHandler(BeginAsyncOperation),
            
new EndEventHandler(EndAsyncOperation),
            
new EndEventHandler(TimeoutAsyncOperation),
            
null
        );
        RegisterAsyncTask(task);
    }


    IAsyncResult BeginAsyncOperation(
object sender, EventArgs e, 
        AsyncCallback cb, 
object state)
    
{
        _request 
= WebRequest.Create("http://msdn.microsoft.com");
        
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();
            }

        }


        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/>");
        }


        Output.Text 
= builder.ToString();
    }


    
void TimeoutAsyncOperation(IAsyncResult ar)
    
{
        Output.Text 
= "Data temporarily unavailable";
    }

}

   
以下是转自MS网站的一篇

ASP.NET 2.0 中的异步页

ASP.NET 2.0 极大地简化了生成异步页的方式。首先使用该页的 @ Page 指令引入 Async=“true” 属性,如下所示:

在后台,这会通知 ASP.NET 在该页中实现 IhttpAsyncHandler。接下来,您在该页生存期的早期(例如,在 Page_Load 时)调用新的 Page.AddOnPreRenderCompleteAsync 方法来注册一个 Begin 方法和一个 End 方法,如以下代码所示:

AddOnPreRenderCompleteAsync (
new BeginEventHandler(MyBeginMethod),
new EndEventHandler (MyEndMethod)
);

接下来的操作比较有趣。该页经历其常规处理生命周期,直到 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 中的代码隐藏类提供一个示例。响应页包含一个 ID 为“Output”的 Label 控件。该页使用 System.Net.HttpWebRequest 类提取 http://MSDN.microsoft.com 的内容。然后,它分析返回的 HTML,并将它发现的全部 HREF 目标列表写出到 Label 控件。

由于 HTTP 请求需要较长时间才能返回,因此,AsyncPage.aspx.cs 异步执行对它的处理。它在 Page_Load 中注册 Begin 和 End 方法,并且在 Begin 方法中,它调用 HttpWebRequest.BeginGetResponse 启用一个异步 HTTP 请求。BeginAsyncOperation 将由 BeginGetResponse 返回的 IAsyncResult 返回到 ASP.NET,导致当 HTTP 请求完成时,ASP.NET 调用 EndAsyncOperation。EndAsyncOperation 进而分析该内容并将结果写入 Label 控件,之后进行呈现,并且 HTTP 响应返回到浏览器。


图 2 同步和异步页处理

图 2 说明 ASP.NET 2.0 同步和异步页之间的区别。当请求同步页时,ASP.NET 为该请求分配线程池中的一个线程,并在该线程上执行页。如果该请求停止执行 I/O 操作,则挂起线程,直到完成操作,从而可以完成该页的生命周期。相反,异步页通常通过 PreRender 事件执行。然后,调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法,之后,该请求处理线程返回线程池。Begin 启动一个异步 I/O 操作,当该操作完成时,ASP.NET 从线程池提取另一个线程并调用 End 方法,并且在该线程上执行该页生命周期的其余部分。


图 3 跟踪输出显示异步页的异步点

对 Begin 的调用标记该页的“异步点”。图 3 中的跟踪准确显示异步点发生在何处。如果调用,则必须在异步点之前调用 AddOnPreRenderCompleteAsync — 即,不晚于该页的 PreRender 事件。

返回页首返回页首

异步数据绑定


通常情况下,ASP.NET 页并不使用 HttpWebRequest 直接请求其他页,但它们通常查询数据库并对结果进行数据绑定。因此,您将如何使用异步页执行异步数据绑定呢? 4 中的代码隐藏类显示进行此操作的一种方式。

AsyncDataBind.aspx.cs 与 AsyncPage.aspx.cs 使用相同的 AddOnPreRenderCompleteAsync 模式。但是,AsyncDataBind.aspx.cs 的 BeginAsyncOperation 方法调用 ADO.NET 2.0 中的新方法 SqlCommand.BeginExecuteReader(而非 HttpWebRequest.BeginGetResponse),以执行一个异步数据库查询。当调用完成时,EndAsyncOperation 调用 SqlCommand.EndExecuteReader 以获取 SqlDataReader,然后将其存储在私有字段中。在用于 PreRenderComplete 事件(在异步操作完成但呈现该页之前引发)的事件处理程序中,AsyncDataBind.aspx.cs 之后将 SqlDataReader 绑定到 Output GridView 控件。从外观上看,该页类似于使用 GridView 呈现数据库查询结果的普通(同步)页。但是在内部,该页更具可伸缩性,因为它并不挂起线程池线程以等待查询返回。

返回页首返回页首

异步调用 Web 服务


另一个通常由 ASP.NET Web 页执行的、与 I/O 相关的任务是调出 Web 服务。由于 Web 服务调用花费较长时间才能返回,因此,执行它们的页是用于异步处理的理想选择。

5 显示生成调出 Web 服务的异步页的方式。它使用 1 4 中相同的 AddOnPreRenderCompleteAsync 机制。该页的 Begin 方法通过调用 Web 服务代理的异步 Begin 方法启动一个异步 Web 服务调用。该页的 End 方法在私有字段中缓存对 Web 方法返回的 DataSet 的引用,并且 PreRenderComplete 处理程序将 DataSet 绑定到 GridView。作为参考,该调用的目标 Web 方法如以下代码所示:

[WebMethod]
public DataSet GetTitles ()
{
string connect = WebConfigurationManager.ConnectionStrings
["PubsConnectionString"].ConnectionString;
SqlDataAdapter adapter = new SqlDataAdapter
("SELECT title_id, title, price FROM titles", connect);
DataSet ds = new DataSet();
adapter.Fill(ds);
return ds;
}

这只是其中一种方式,但并不是唯一的方式。.NET Framework 2.0 Web 服务代理支持两种对 Web 服务进行异步调用的机制。一个是 .NET Framework 1.x 和 2.0 Web 服务代理中的每方法 Begin 和 End 方法。另一个是仅由 .NET Framework 2.0 的 Web 服务代理提供的新 MethodAsync 方法和 MethodCompleted 事件。

如果一个 Web 服务有一个名为 Foo 的方法,那么除了具有名为 Foo、BeginFoo 和 EndFoo 的方法外,.NET Framework 版本 2.0 Web 服务代理还包括名为 FooAsync 的方法和名为 FooCompleted 的事件。可以通过注册 FooCompleted 事件的处理程序并调用 FooAsync 来异步调用 Foo,如下所示:

proxy.FooCompleted += new FooCompletedEventHandler (OnFooCompleted);
proxy.FooAsync (...);
...
void OnFooCompleted (Object source, FooCompletedEventArgs e)
{
// Called when Foo completes
}

当异步调用由于 FooAsync 完成而开始时,将引发 FooCompleted 事件,从而导致调用 FooCompleted 事件处理程序。包装该事件处理程序 (FooCompletedEventHandler) 的委托和传递给它的第二个参数 (FooCompletedEventArgs) 都随 Web 服务代理一起生成。可通过 FooCompletedEventArgs.Result 访问 Foo 的返回值。

6 展示使用 MethodAsync 模式异步调用 Web 服务的 GetTitles 方法的代码隐藏类。从功能上讲,该页等同于 5 中的页。但其内部实现则大为不同。AsyncWSInvoke2.aspx 包括一个 @ Page Async=“true” 指令,类似于 AsyncWSInvoke1.aspx。但是,AsyncWSInvoke2.aspx.cs 并不调用 AddOnPreRenderCompleteAsync;它注册一个用于 GetTitlesCompleted 事件的处理程序,并调用 Web 服务代理上的 GetTitlesAsync。ASP.NET 仍然延迟呈现该页,直到 GetTitlesAsync 完成。在内部,当异步调用开始以及完成时,它使用 System.Threading.SynchronizationContext 的一个实例(2.0 的一个新类)接收通知。

使用 MethodAsync 而非 AddOnPreRenderCompleteAsync 实现异步页有两个优势。首先,MethodAsync 将模拟、区域性和 HttpContext.Current 注入 MethodCompleted 事件处理程序,而 AddOnPreRenderCompleteAsync 则不然。其次,如果该页进行多个异步调用,而且必须延迟呈现直到所有调用完成,则使用 AddOnPreRenderCompleteAsync 要求您生成一个在所有调用完成前保持无信号状态的 IasyncResult。使用 MethodAsync,这样的操作就不是必需的;您只需放置这些调用(数量不限),ASP.NET 引擎延迟该呈现阶段,直到最后一个调用返回。

返回页首返回页首

异步任务


MethodAsync 是从异步页进行多个异步 Web 服务调用并延迟呈现阶段直到所有调用完成的一个简便方法。但如果您想在一个异步页中执行若干异步 I/O 操作,而且这些操作不涉及 Web 服务,那该如何呢? 这么说,可以反过来生成一个 IAsyncResult,它可以返回到 ASP.NET 以允许它了解最后一个调用何时完成的吗? 幸运的是,答案是否定的。

在 ASP.NET 2.0 中,System.Web.UI.Page 类引入了另一个方法来简化异步操作: RegisterAsyncTask。RegisterAsyncTask 比 AddOnPreRenderCompleteAsync 具有四个优势。首先,除了 Begin 和 End 方法,RegisterAsyncTask 还允许您注册当异步操作长时间无法完成时调用的超时方法。您可以通过在该页的 @ Page 指令中包含 AsyncTimeout 属性以声明性方式设置超时。AsyncTimeout="5" 将超时设置为 5 秒。第二个优势是,您可以在一个请求中多次调用 RegisterAsyncTask 来注册若干异步操作。和使用 MethodAsync 一样,ASP.NET 延迟呈现该页,直到所有操作完成。第三,您可以使用 RegisterAsyncTask 的第四个参数将状态传递给 Begin 方法。最后,RegisterAsyncTask 将模拟、区域性和 HttpContext.Current 注入 End 和 Timeout 方法。正如本文前面提到的,使用 AddOnPreRenderCompleteAsync 注册的 End 方法的情况则不然。

在其他方面,依赖于 RegisterAsyncTask 的异步页与依赖于 AddOnPreRenderCompleteAsync 的异步页相类似。它仍然需要 @ Page 指令(或等效的编程指令,它会将该页的 AsyncMode 属性设置为 true)中的 Async=“true” 属性,而且它仍然与平时一样通过 PreRender 事件执行,此时调用使用 RegisterAsyncTask 注册的 Begin 方法,而且进一步保持请求处理直到最后一个操作完成。例如, 7 中的代码隐藏类在功能上与 1 中的等效,但是它使用 RegisterTaskAsync 而非使用 AddOnPreRenderCompleteAsync。请注意名为 TimeoutAsyncOperation 的超时处理程序,如果 HttpWebRequest.BeginGetRequest 长时间无法完成,将调用该处理程序。相应的 .aspx 文件包括一个将超时间隔设置为 5 秒的 AsyncTimeout 属性。还请注意传给 RegisterAsyncTask 的第四个参数(可用于将数据传送到 Begin 方法)的 null。

RegisterAsyncTask 的主要优势在于,它允许异步页引发多个异步调用,并延迟呈现直到所有调用完成。它也很好地适用于单个异步调用,而且它提供了 AddOnPreRenderCompleteAsync 不具有的超时选项。如果生成一个只进行一个异步调用的异步页,您可以使用 AddOnPreRenderCompleteAsync 或 RegisterAsyncTask。但对于放置两个以上异步调用的异步页,RegisterAsyncTask 极大地简化了您的操作。

由于超时值是每页而非每调用设置,因此您可能想知道是否能改变单个调用的超时值。简单的回答是否。您可以通过以编程方式修改页的 AsyncTimeout 属性,逐个请求地更改超时,但是您无法将不同超时分配给从同一请求初始化的不同调用。

返回页首返回页首

包装它


现在,您已经了解了 ASP.NET 2.0 中异步页的实质。它们在即将推出的 ASP.NET 版本中非常易于实现,并且其体系结构允许您在一个请求中批处理多个异步 I/O 操作,并延迟该页的呈现直到所有操作完成。通过与异步 ADO.NET 和 .NET Framework 中的其他新异步功能相结合,异步 ASP.NET 页针对因充满线程池而限制可伸缩性的 I/O 绑定请求问题提供了解决方案。

当生成异步页时最后需要注意的一点是,不应该启动来自 ASP.NET 使用的同一线程池的异步操作。例如,在页的异步点调用 ThreadPool.QueueUserWorkItem 会起反作用,因为该方法来自线程池,从而导致纯粹获取用于处理请求的零线程。相反,调用内置于 Framework 中的异步方法(例如,方法 HttpWebRequest.BeginGetResponse 和 SqlCommand.BeginExecuteReader)通常认为是安全的,因为这些方法倾向于使用完成端口实现异步行为。

下载代码:WickedCode0510.rar

posted on 2010-09-13 02:46  米高佐敦  阅读(634)  评论(0编辑  收藏  举报