2014-01-21 4 views
2

Я использую asp.net v4 C#, и у меня есть список адресов электронной почты. Я хочу, чтобы один из моих администраторов мог ввести сообщение, нажать «ОТПРАВИТЬ» и отправить электронные письма по одному.async task in loop in asp.net v4

Лучший способ, по-моему, использовать методы async в .net? OnClick из кнопки отправки, я беру список адресов электронной почты, затем вызываю метод async. Я просто не знаю, как заставить его перебирать список один за другим и отключать электронную почту.

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

Вот что я до сих пор (слепленный из учебники/сообщений здесь)

protected void btnSend_Click(object sender, EventArgs e) 
{ 
    //get a list of email addresses and send to them 
    //these will come from the database once testing comp 
    List<string> emails = new List<string>(); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 
    emails.Add("[email protected]"); 

    SendingDelegate worker = new SendingDelegate(DoSend); 
    AsyncCallback completedCallback = new AsyncCallback(DoSendCompletedCallBack); 

    lblThreadDetails.Text = "sending to " + emails.Count.ToString() + " email addresses"; 

    worker.BeginInvoke(completedCallback, AsyncOperationManager.CreateOperation(null)); 
    sending = true; 

} 

//boolean flag which indicates whether the async task is running 
private bool sending = false; 

private delegate bool SendingDelegate(); 

private bool DoSend() 
{ 
    //send messages 
    //emails sent here and saved in the DB each time 

    //give the user some feed back on screen. X should be the email address. 
    lblThreadDetails.Text = "processing " + x.ToString(); 
    Thread.Sleep(1000); 
    return false; 
} 

private void DoSendCompletedCallBack(IAsyncResult ar) 
{ 
    //get the original worker delegate and the AsyncOperation instance 
    SendingDelegate worker = (SendingDelegate)((AsyncResult)ar).AsyncDelegate; 

    //finish the asynchronous operation 
    bool success = worker.EndInvoke(ar); 
    sending = false; 

    if (success) 
    { 
     //perform sql tasks now that crawl has completed 
     lblThreadDetails.Text = "all done!"; 
    } 
} 

я в основном нужно поставить вызов функции асинхронной в петле, где я иду по списку электронной почты адреса.

Этот подход имеет смысл?

+0

Tangent: вы знаете, что вам больше не нужны «новые» объекты делегата? По крайней мере, для меня это сделает код более читаемым, так как вам не нужно трассировать обратно туда, где указана переменная делегата. – millimoose

+0

I.e. вы можете использовать '(DoSend as Action) .BeginInvoke (DoSendCompletedCallback, AsyncOperationManager.CreateOperation (null))' – millimoose

+1

Кроме того, есть одна вопиющая проблема не в вашем подходе, а в вашем тестовом жгуте, который обновляет GUI из фоновых операций. Большинство систем графического интерфейса являются однопоточными, то есть создание и обновление пользовательского интерфейса должно происходить в потоке, выполняющем цикл событий. – millimoose

ответ

2

Предполагаете, что вы не можете использовать ASP.NET 4.5 и async/await, что может быть идеальным решением для этого случая (см. this и this для получения дополнительной информации).

Однако с ASP 4.0 вы все еще можете использовать асинхронный код на своей странице с PageAsyncTask и Page.RegisterAsyncTask. Это продлит срок службы запроса, пока задача асинхронной не завершена:

PageAsyncTask asyncTask = new PageAsyncTask(
    slowTask.OnBegin, slowTask.OnEnd, slowTask1.OnTimeout, 
    "AsyncTaskName", true); 

Затем вы вызываете worker.BeginInvoke/EndInvoke из OnBegin/OnEnd. MSDN имеет complete sample code.

Для решения самого вопроса:

делает ли такой подход имеет смысл? Спасибо за любую информацию.

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

Очевидно, что вы здесь делаете фоновый поток и выполняете некоторую синхронную операцию над этим потоком, например Thread.Sleep(1000) внутри вашего DoSend(). Это имеет смысл для приложения пользовательского интерфейса на стороне клиента (чтобы пользовательский интерфейс реагировал).

Однако для вашего серверного приложения вы не получаете никакого преимущества: по крайней мере один поток (тот, который начался с BeginInvoke) остается заблокированным во время вашей текущей операции.

Вы также можете позвонить DoSend() непосредственно в исходную цепочку, обрабатывающую HTTP-запрос (внутри btnSend_Click), без BeginInvoke. В этом случае ваше приложение может даже немного масштабироваться, потому что оно будет меньше переключения потоков.

Теперь, возможно, вы можете перефакторировать свой код, чтобы использовать чистые асинхронные интерфейсы IO/Network-bound, которые не требуют выделенного потока. Вот что сделало бы ваше приложение намного лучше. Прочитайте 's There Is No Thread сообщение в блоге, чтобы получить лучшее представление о том, что я говорю.