Пример асинхронной обработки страницы в веб-формах ASP.net (.NET 2.0) - PullRequest
9 голосов
/ 16 ноября 2010

Может ли кто-нибудь предоставить мне простой пример асинхронной обработки страниц в ASP.NET Webforms 2.0 (я использую VS 2010, поэтому новый синтаксис, такой как лямбды, в порядке)?что я не хочу связывать потоки IIS.

Для простоты, скажем, мой текущий код выглядит следующим образом:

protected void Page_Load(object sender, EventArgs e)
{
    string param1 = _txtParam1.Text;
    string param2 = _txtParam2.Text;

    //This takes a long time (relative to a web request)
    List<MyEntity> entities = _myRepository.GetEntities(param1, param2);

    //Conceptually, I would like IIS to bring up a new thread here so that I can
    //display the data after it has come back.
    DoStuffWithEntities(entities);

}

Как я могу изменить этот код, чтобы он был асинхронным?Давайте предположим, что я уже установил async = "true" на странице aspx.

EDIT

Мне кажется, я понял, как получить то, что я ищу.Я поместил пример кода в ответ здесь .Не стесняйтесь указывать на любые недостатки или изменения, которые могут быть сделаны.

Ответы [ 3 ]

16 голосов
/ 29 июня 2012

Я спросил некоторых людей из команды ASP.NET.Вот их ответ по электронной почте мне, а теперь и вам.

Все, что в конечном итоге делает код, это раскручивает новый поток и выполняет вызов делегата в этом потоке.Итак, теперь запущены два потока: поток запроса и новый поток.Следовательно, этот образец на самом деле имеет худшую производительность, чем исходный синхронный код.

См. http://www.asp.net/web-forms/tutorials/aspnet-45/using-asynchronous-methods-in-aspnet-45 для примера того, как писать и использовать асинхронные методы в ASP.NET.*

6 голосов
/ 16 ноября 2010

Вот простой пример асинхронной обработки.

   protected void Page_Load(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
        ThreadPool.QueueUserWorkItem(state => Dokimes_Programming_multithread_QueryWorkThead.ThreadProc2());

        Debug.Write("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        // Thread.Sleep(4000);

        txtDebug.Text += "ended";

        Debug.Write("end.");
    }


    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo)
    {

        // No state object was passed to QueueUserWorkItem, so  stateInfo is null.
        Debug.Write(" Hello from the thread pool 1.");
    }

    static void ThreadProc2()
    {
        // No state object was passed to QueueUserWorkItem, so  stateInfo is null.
        Debug.Write("Hello from the thread pool 2.");
    }

Другой способ

Вы можете использовать PageAsyncTask, см. Здесь полный пример:
http://msdn.microsoft.com/en-us/library/system.web.ui.pageasynctask.aspx

Что-то вроде

clAsynCustomObject oAsynRun = new clAsynCustomObject();

PageAsyncTask asyncTask = new PageAsyncTask(oAsynRun.OnBegin, oAsynRun.OnEnd, oAsynRun.OnTimeout, null, true);
Page.RegisterAsyncTask(asyncTask);
Page.ExecuteRegisteredAsyncTasks();
0 голосов
/ 17 ноября 2010

Я думаю, что я обнаружил, как делать то, что я хотел достичь ... хотя это может быть не лучшим способом, не стесняйтесь вмешиваться.

На момент написания в этой теме был только один ответ, от Аристоса . В то время как он привел пример выполнения асинхронного запроса, я хотел, чтобы ASP.NET выполнил какой-то длительный метод, освободил поток IIS, чтобы он мог быть доступен для обслуживания других запросов, а затем вернулся, когда метод законченный.

Вот что я придумал, используя тот же (или похожий) пример из вопроса:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Web.UI;

namespace WebApplication2
{
    public class MyEntity
    {
        public string Name { get; set; }
    }

    public class MyRepository
    {
        public List<MyEntity> GetEntities(string param1, string param2)
        {
            Thread.Sleep(10000);
            return new List<MyEntity> {new MyEntity {Name = "John Smith"}};
        }
    }

    public partial class Default : Page
    {
        private readonly MyRepository _myRepository = new MyRepository();
        private List<MyEntity> _myEntities;

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        private void DoStuffWithEntities()
        {
            Response.Write("<br/><br/><b>" + _myEntities[0].Name + "</b><br/><br/>");
        }

        protected void _btnProcess_Click(object sender, EventArgs e)
        {
            AddOnPreRenderCompleteAsync(BeginExecution, EndExecution, null);
        }

        private void GetEntities()
        {
            string param1 = _txtParam1.Text;
            string param2 = _txtParam2.Text;


            //This takes a long time (relative to a web request)
            _myEntities = _myRepository.GetEntities(param1, param2);
        }

        private IAsyncResult BeginExecution(object sender, EventArgs e, AsyncCallback callback, object state)
        {
            var t = new ThreadStart(GetEntities);
            return t.BeginInvoke(callback, null);
        }

        private void EndExecution(IAsyncResult result)
        {
            //Conceptually, I would like IIS to bring up a new thread here so that I can
            //display the data after it has come back.
            DoStuffWithEntities();
        }
    }
}
...