Search Results for '비동기페이지'


1 POSTS

  1. 2010/03/08 ASP.NET 2.0의 비동기 페이지.. by jincaesar

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 메서드의 작업은 데이터베이스 쿼리 또는 웹 서비스 호출 같은 비동기 작업을 실행하고 즉시 반환한느 것이다.
이 때, 요청에 할당된 스레드가 스레드 풀로 돌아간다.
또한 Begin 메서드는 ASP.NET에서 비동기 작업이 완료되었음을 알 수 있도록 IAsyncResult를 반환하며, 이 때 ASP.NET은 스레드 풀에서 스레드를 추출하여 End 메서드를 호출한다.
End가 반환되면 ASP.NET은 렌더링 단계가 포함된 페이지 주기의 나머지 부분을 수행한다.
Begin이 반환되고 End가 호출되는 사이에 요청 처리 스레드는 자유롭게 다른 요청에 서비스를 제공할 수 있고 렌더링은 End가 호출될 때까지 지연된다.
또한 .NET Framework 버전 2.0에서는 다양한 방법으로 비동기 작업을 수행하기 때문에 대개의 경우는 IAsyncResult 조차 구현할 필요가 없으며 대신 Framework가 이를 구현한다.

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 AsyncPage : System.Web.UI.Page
{
    private WebRequest _request;

    void Page_Load (object sender, EventArgs e)
    {
        AddOnPreRenderCompleteAsync (
            new BeginEventHandler(BeginAsyncOperation),
            new EndEventHandler (EndAsyncOperation)
        );
    }

    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("
"); } Output.Text = builder.ToString (); } }

위의 예제에서 해당 페이지에는 ID가 "Output"인 Label 컨트롤이 있다.
페이지는 System.Net.HttpWebRequest 클래스를 사용하여 http://msdn.microsoft.com의 내용을 가져온다.
그런 다음, 반환된 HTML 구문을 분석하고 Label 컨트롤에 찾아낸 모든 HREF 대상 목록을 작성한다.
HTTP 요청이 반환되려면 오랜 시간이 걸릴 수 있기 때문에 AsyncPage.aspx.cs는 비동기 방식으로 처리를 수행한다.
AsyncPage.aspx.cs는 Page_Load에 Begin 및 End 메서드를 등록한다.
Begin 메서드에서는 HttpWebRequest.BeginGetResponse를 호출하여 비동기 HTTP 요청을 실행한다.
BeginAsyncOperation은 ASP.NET에 BeginGetResponse가 반환한 IAsyncResult 반환하고, 그 결과 ASP.NET에서 EndAsyncOperation을 호출하여 HTTP 요청이 완료된다.
그러면 EndAsyncOperation에서 내용을 구문 분석하고 Label 컨트롤에 결과를 작성한다.
그런 다음, 렌더링이 발생하며 HTTP 응답은 브라우저로 돌아간다.

동기 대 비동기 페이지 처리
그림 2 동기대 비동기 페이지 처리

그림 2에서는 ASP.NET 2.0의 동기 페이지와 비동기 페이지 간의 차이를 보여준다.
동기 페이지가 요청되면 ASP.NET은 스레드 풀의 스레드에 요청을 할당하고 해당 스레드로 페이지를 실행한다.
요청 I/O 작업수행을 위해 일시 중지되면 스레드는 작업이 끝나고 페이지 주기가 완료될 때까지 묶여 있다.
반면 비동기 페이지는 PreRender 이벤트가 처리되는 동안에도 정상적으로 실행된다.
그러면 AddOnPreRenderCompleteAsync를 사용하여 등록한 Begin 메서드가 호출된 후 요청 처리 스레드가 스레드 풀로 돌아간다.
Begin 메서드는 비동기 I/O 작업을 실행하고 작업이 끝나면 ASP.NET이 스레드 풀에서 또 다른 스레드를 가져와 End 메서드를 호출하고 해당 스레드로 페이지 주기의 나머지 부분을 실행한다.
Begin을 호출하면 페이지의 "비동기 지점"이 표시된다.
AddOnPreRenderCompleteAsync를 호출하는 경우 비동기 지점 이전에 호출해야 한다.
즉, 페이지의 PreRender 이벤트가 발생한 후에는 호출할 수 없다.

비동기 데이터 바인딩
ASP..NET 페이지에서 직접 HttpWebRequest를 사용하여 다른 페이지를 요청하는 것은 흔치 않지만 데이터베이스를 쿼리하고 결과를 데이터 바인딩하는 것은 흔한일이다.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Configuration;

public partial class AsyncDataBind : System.Web.UI.Page
{
    private SqlConnection _connection;
    private SqlCommand _command;
    private SqlDataReader _reader;


    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)
    {
        string connect = WebConfigurationManager.ConnectionStrings
            ["PubsConnectionString"].ConnectionString;
        _connection = new SqlConnection(connect);
        _connection.Open();
        _command = new SqlCommand(
            "SELECT title_id, title, price FROM titles", _connection);
        return _command.BeginExecuteReader (cb, state);
    }

    void EndAsyncOperation(IAsyncResult ar)
    {
        _reader = _command.EndExecuteReader(ar);
    }

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

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

위의 AsyncDataBind.asp.cs는 AsyncPage.aspx.cs에서 사용하는 것과 같은 AddOnPreRenderCompleteAsync 패턴을 사용한다.
하지만 BeginAsyncOperation 메서드는 HttpWebRequest.BeginGetResponse를 호출하지 않고 SqlCommand.BeginExecuteReader를 호출하여 비동기 데이터베이스 쿼리를 수행한다.
호출이 완료되면 EndAsyncOperation은 SqlCommand.EndExecuteReader를 호출하여 SqlDataReader를 가져온 다음 이를 개인 필드에 저장한다.
비동기 작업이 완료된 후와 페이지가 렌더링 되기 전에 발생하는 PreRenderComplete 이벤트의 이벤트 처리기에서 SqlDataReader를 Output GridView 컨트롤에 바인딩한다.
표면적으로 이 페이지는 Gridview를 사용하여 데이터베이스 쿼리 결과를 렌더링하는 일반적인(동기) 페이지처럼 보인다.
하지만 내부적으로 이 페이지는 스레드 풀 스레드를 쿼리가 반활될 때까지 대기하도록 묶어 두지 않기 때문에 확장성이 훨씬 뛰어나다.

비동기식 웹 서비스 호출
ASP.NET 웹 페이지에서 일반적으로 수행하는 또 다른 I/O 관련 작업은 웹 서비스 호출이다.
웹 서비스 호출은 반환까지 오랜 시간이 걸릴 수 있기 때문에 웹 서비스 호출을 수행하는 페이지는 비동기식으로 처리하기에 매우 적합하다.

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();
    }
}


--------------------------------------------------------------------------------
Figure 6 AsyncWSInvoke2.aspx.cs

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();
    }
}


--------------------------------------------------------------------------------
Figure 7 AsyncPageTask.aspx.cs

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("
"); } Output.Text = builder.ToString(); } void TimeoutAsyncOperation(IAsyncResult ar) { Output.Text = "Data temporarily unavailable"; } }

AddOnPreRenderCompleteAsync 메커니즘을 사용한다.
페이지의 Begin 메서드는 웹 서비스 프록시의 비동기 Begin 메서드를 호출하여 비동기 웹 서비스 호출을 실행한다.
페이지의 End 메서드는 웹 메서드가 반환하는 DataSet에 대한 참조를 비공개 필드에 캐시하고, PreRenderComplete 처리기는 DataSet을 GridView에 바인딩한다.
다음 코드에는 참고를 위해 호출 대상 웹 메서드가 나와 있다.

[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 웹 서비스 프록시는 웹 서비스의 비동기 호출에 사용할 수 있는 두 가지 메커니즘을 지원한다. 하나는 .NET Framework 1.x 및 2.0 웹 서비스 프록시에서 사용했던 메서드별 Begin 및 End 메서드이다. 다른 하나는 .NET Framework 2.0 웹 서비스 프록시에만 있는 새로운 MethodAsync 메서드와 MethodCompleted 이벤트이다. 웹 서비스에 Foo라는 메서드가 있는 경우 .NET Framework 버전 2.0 웹 서비스 프록시에는 Foo, BeginFoo및 EndFoo라는 메서드 외에도 FooAsync라는 메서드와 FooCompleted라는 이벤트가 들어있다. 다음과 같이 FooCompleted 이벤트에 대한 처리기를 등록하고 FooAsync를 호출하여 Foo를 비동기적으로 호출할 수 있다.

proxy.FooCompleted += new FooCompletedEventHandler (OnFooCompleted);
proxy.FooAsync (...);
...
void OnFooCompleted (Object source, FooCompletedEventArgs e)
{
    // Foo가 완료될 때 호출됩니다
}

FooAsync로 시작된 비동기 호출이 완료되면 FooCompleted 이벤트가 발생하여 FooCompleted 이벤트 처리기가호출된다.
이벤트 처리기(FooCompetedEventHandler)를 래핑하는 대리자와 이벤트처리기에 전달되는 두 번째 매개변수(FooCompletedEventArge)는 모두 웹 서비스 프록시와 함께 생성된다.
그러면 FooCompledEvent.Args.Result를 통해 Foo의 반환 갑에 액세스 할 수 있다.

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();
    }
}


--------------------------------------------------------------------------------
Figure 7 AsyncPageTask.aspx.cs

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("
"); } Output.Text = builder.ToString(); } void TimeoutAsyncOperation(IAsyncResult ar) { Output.Text = "Data temporarily unavailable"; } }

위의 소스에서는 MethodAsync 패턴을 사용하여 웹 서비스의 GetTitles 메서드를 비동기적으로 호출하는 코드 숨김 클래스를 보여준다.
이 페이지는 기능 면에서 위의 페이지와 동일하다.
하지만 내부적으로는 크게 다르다.
AsyncWSInvoke2.aspx에도 AsyncWSInvoke1.asp와 마찬자기로 @Page Async="true" 지시문이 포함된다.
하지만 AsyncWSInvoke2.aspx.cs는 AddOnPreRenderCompleteAsync를 호출하지 않는다.
대신 GetTitlesCompleted 이벤트에 대해 처리기를 등록하고 웹 서비스 프록시로 GetTitlesAsnc를 호출한다.
ASP.NET은 GetTitlesAsync가 완료될 때까지 계속해서 페이지 렌더링을 연기한다.
내부적으로는 System.threading.SynchronizationContext의 인스턴스를 사용하여 비동기 호출의 시작 및 완료 시기에 대한 알림을 수신한다.

AddOnPreRenderCompleteAsync 대신 MethodAsync를 사용하여 비동기 페이지를 구현하면 두가지 이점이 있다.
첫째, MethodAsync는 가장, culture 및 HttpContext.Current를 MethodCompleted 이벤트 처리기에 전달하지만 AddOnPreRenderCompleteAsync는 그렇지 않다.
둘째, 페이지에서 여러 비동기 호출을 하고 모든 호출이 완료될 때까지 렌더링을 연기해야 하는 경우, AddOnPreRenderCompleteAsync를 사용하려면 모든 호출이 완료될 때 까지 통보를 받지 않도록 IAsyncResult를 조작해야 한다.
MethodAsync를 사용하면 이러한 조작이 필요없다.
사용자는 원하는 만큼 호출할 수 있으며 ASP.NET 엔진은 마지막 호출이 반환될 때까지 렌더링 단계를 연기한다.

비동기 작업

MethodAsync를 사용하면 비동기 페이지에서 여러 비동기 웹 서비스를 호출하고 모든 호출이 완료될 때까지 렌더링 단계를 연기하는 작업을 간단히 수행할 수 있다.
하지만 비동기 페이지에서 여러 비동기 I/0 작업을 수행하는 경우, 작업이 웹 서비스와 관련되어 있지 않으면 RegisterAsyncTask를 사용한다.

RegisterAsyncTask는 AddOnPreRenderCompleteAsync에 비해 네가지 이점이 있다.
첫째, RegisterAsyncTask는 Begin 및 End 메서드 외에도 비동기 작업이 너무 오래 걸릴 경우 호출되는 시간 제한 메서드를 등록할 수 있다.
시간 제한은 페이지의 @Page 지시문에 AsyncTimeout 특성을 포함시켜 선언적으로 설정할 수 있다.
AsyncTimeout="5"인 경우 시간 제한은 5초로 설정된다.
둘째, 한 요청에 RegisterAsyncTask를 여러 번 호출하여 여러 개의 비동기 작업을 등록할 수 있다는 점이다.
MethodAsync에서와 마찬가지로, ASP.NET은 모든 작업이 완료될 때까지 페이지의 렌더링을 연기한다.
셋째, RegisterAsyncTash의 네 번째 매개 변수를 사용하여 Begin 메서드에 상태를 전달할 수 있다.
마지막으로 ,  RegisterAsyncTask는 가장, culture 및 HttpContext.Current를 End 및 Timeout 메서드에 전달한다.
하지만 앞서 언급했듯이, 이는 AddOnPreRenderCompleteAsync로 등록된 End 메서드에는 적용되지 않는다.

다른 측면에서 보면 RegisterAsyncTask를 사용하는 비동기 페이지는 AddOnPreRenderCompleteAsync를 사용하는 비동기 페이지와 유사하다.
여전히 @Page 지시문에 Async="true" 특성이 포함되어야 하고(또는 페이지의 AsyncMode 속성을 True로 설정하도록 프로그래밍 관점에서 동일한 작업이 필요함) PreRender 이벤트를 통해 정상적으로 수행되지만 이 때 RegisterAsyncTask를 사용하여 등록된 Begin 메서드가 호출되고 추가 요청 처리는 마지막 작업이 완료될 때까지 연기된다.

예를 들어, 아래와 같은 코드 숨김 클래스는 첫번째 예제와 기능 면에서는 동일하지만 AddOnPreRenderCompleteAsync 대신 RegisterTaskAsync를 사용한다.
HttpWebRequest.BeginGetRequest를 완료하는 데 너무 오랜 시간이 걸리면 TimeoutAsyncOperation이라는 시간 제한 처릭가 호출된다.
해당 .aspx 파일에는 시간 제한 간격을 5초로 설정하는 AsyncTimeout 특성이 있다.
또한 데이터를 Begin 메서드에 전달하는 데 사용 되었을 수 있는 RegisterAsyncTask의 네 번째 매개 변수에는 null이 전달 된다.

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("
"); } Output.Text = builder.ToString(); } void TimeoutAsyncOperation(IAsyncResult ar) { Output.Text = "Data temporarily unavailable"; } }

RegisterAsyncTask의 가장 큰 이점은 비동기 페이지가 여러 비동기 호출을 수행하고  모든 호출이 완료될 때까지 렌더링을 연기할 수 있다는 것이다.
물론 한 번의 비동기 호출에도 완벽하게 작동하며 AddOnPreRenderCompleteAsync에는 없는 시간 제한 옵션도 제공한다.
비동기 호출을 한 번만 수행하는 비동기 페이지를 작성하는 경우에는 AddOnPreRenderCompleteAsync 또는 RegisterAsyncTask를 사용한다.
하지만 비동기 호출을 두번 이상 수행하는 비동기 페이지의 경우에는 RegisterAsyncTask를 사용해야 작업이 훨씬 수월하다.

시간 제한 값이 호출별이 아닌 페이지별 설정이기 때문에 호출마다 시간 제한 값을 다르게 설정할 수 는 없다.
페이지의 AsyncTimeout 속성을 프로그래밍 방식으로 수정하여 요청별로 시간 제한을 다르게 할 수는 있지만 같은 요청에서 비롯된 여러 호출에 다른 시간 제한 값을 할당할 수는 없다.

요약

지금까지 ASP.NET 2.0의 비동기 페이지에 대해 개략적으로 살펴 보았다.
비동기 페이지는 아키텍처가 한 요청에 여러 비동기 I/O 작업을 일괄 처리하고 모든 작업이 완료될 때까지 페이지 렌더링을 연기할 수 있도록 설계되었다.
비동기 ADO.NET 및 기타 .NET Framework의 새로운 비동기 기능을 결합시킨 비동기 ASP.NET 페이지는 스레드 풀을 포화시켜 확정성을 떨어뜨리는 I/O바인딩 요청 문제에 강력하고 편리한 해결책을 제공한다.

비동기 페이지를 작성할 때 주의해야 할 마지막 사항은 ASP.NET에서 사용하는 것과 동일한 스레드 풀에서 가져온 비동기 작업은 실행할 수 없다는 점이다.
예를 들어 페이지의 비동기 지점에서 ThreadPool.QueueUserWorkItem을 호출하면 메서드를 스레드 풀에서 가져오기 때문에 효율이 떨어지고 결과적으로 요청을 처리할 수 있는 스레드가 없어지는 상황이 발생한다.
반대로 Framework에 내장된 비동기 메서드를 호출하면 HttpWebRequest.BeginGetResopnse 및 SqlCommadn.BeginExecuteReader 같은 메서드는 주로 완료 포트를 사용하여 비동기 동작을 구현하기 때문에 대체로 안전하다고 할 수 있다.

출처 : http://www.microsoft.com/korea/msdn/msd ··· ult.aspx
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by jincaesar

2010/03/08 14:11 2010/03/08 14:11
, ,
Response
No Trackback , No Comment
RSS :
http://jincaesar.maru.net/tc/rss/response/17