このコードのチャンクを機能させるのに問題があります (長くなってすみません)。コードは無菌化され、問題の診断に関連する部分のみが表示されます。
コンソール アプリから実行すると正常に動作します。しかし、ASP.NET アプリから Utlities.SendBulkEmail が呼び出されると、BulkEmailCompleted ルーチンは起動されず、m_CompletedWorkers カウンターをインクリメントするのはこのルーチンです。
SendBulkEmail ルーチンをリファクタリングして、BackgroundWorker の代わりに AsyncOperationManager を使用する方法を教えてください。結果が返されるスレッドを保証できます。
SendBulkEmail ルーチン自体はマルチスレッドではありません。マルチスレッドは foreach ループ内で発生します。
元のコードの基礎は次の Web サイトから取得したと思います: http://www.dotnetfunda.com/articles/article613-background-processes-in-asp-net-web-applications.aspx
Utilities プロジェクトはさまざまなソリューション間で共有されており、ほとんど独立しています。
私はこれを明確にすることを望んでいます。
どんな助けでも大歓迎です。
コードは次のとおりです。
Web サイト プロジェクト内 (Control.ascx.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Configuration;
using <company>.BusinessObjects.Emails;
using <company>.DataAccessors;
using <company>.DataObjects;
using <company>.Enumerations;
using <company>.Interfaces;
using <company>.Utilities;
...
protected void sendButton_OnClick(object sender, EventArgs e)
{
...
if (HasBenefits)
{
ReportingEmails emailer = new ReportingEmails();
...
//Prevent send if nothing selected
if (... > 0)
{
List<EmailOutcome> results = emailer.GenerateNotificationEmailsForEmployer(<some int>, <some list>);
...
}
}
...
}
ビジネスオブジェクトプロジェクトで
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Resources;
using System.Text;
using System.IO;
using <company>.BusinessObjects.Emails.Helpers;
using <company>.DataAccessors;
using <company>.DataObjects;
using <company>.Enumerations;
using <company>.Utilities;
namespace <company>.BusinessObjects.Emails
{
public class ReportingEmails
{
...
public List<EmailOutcome> GenerateNotificationEmailsForEmployer(int employerID, List<int> benefits = null)
{
...
SendNotificationEmails(List<ReportData>, ref emailSuccessByBenefit, true, benefitsToExclude);
return emailSuccessByBenefit;
}
private void SendNotificationEmails(List<ReporterCommsData> reportData, ref List<EmailOutcome> emailSuccessByBenefit, bool isFleet, List<int> benefitsToExclude)
{
Dictionary<int, MailMessage> bulkEmails = new Dictionary<int, MailMessage>();
//build up the set of emails to send
foreach (ReporterCommsData report in reportData)
{
...
if (String.IsNullOrEmpty(report.Email))
{
...
}
else
{
try
{
MailMessage email = null;
...
email = ConstructEmail(<param>, out <param>, <param>);
...
bulkEmails.Add(report.BenefitID, email); //add each email to the bulk email dictionary
...
}
catch (Exception ex)
{
...
}
}
} //end foreach
//do the bulk email send and get the outcomes
try
{
...
emailSuccessByBenefit.AddRange(Utilities.Mail.SendBulkEmail(bulkEmails, credentials));
}
catch (Exception ex)
{
...
}
}
...
}
...
}
ユーティリティ プロジェクトで
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.Threading;
namespace <company>.Utilities
{
...
public class Mail
{
private static List<EmailOutcome> m_MultithreadedEmailSendResults = new List<EmailOutcome>();
private static int m_CompletedWorkers = 0;
...
/// <summary>
/// Sends a large number of emails asynchronously and then reports success of the individual items collectively
/// </summary>
/// <param name="emails">A dictionary of completed MailMessage objects to send out, keyed on an ID</param>
/// <param name="credentials">Network credentials which may be required to send the email</param>
/// <returns>List of EmailOutcome objects signifying the success or failure of sending each individual email</returns>
public static List<EmailOutcome> SendBulkEmail(Dictionary<int, MailMessage> emails, System.Net.NetworkCredential credentials = null)
{
const int NUMBER_OF_THREADS_PER_PROCESSOR = 1;
m_CompletedWorkers = 0;
List<EmailOutcome> results = new List<EmailOutcome>();
List<Dictionary<int, MailMessage>> splitEmailList = new List<Dictionary<int, MailMessage>>();
...
List<BackgroundWorker> workerThreads = new List<BackgroundWorker>();
foreach (Dictionary<int, MailMessage> splitEmails in splitEmailList)
{
// Initialise the parameter array
Object[] parameterArray = new Object[2];
parameterArray[0] = splitEmails;
parameterArray[1] = credentials;
// Runs on function startup
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(BulkEmailWorker);
worker.WorkerReportsProgress = false;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BulkEmailCompleted);
//Add worker to collection
workerThreads.Add(worker);
//Calling the BulkEmailWorker asynchronously
worker.RunWorkerAsync(parameterArray);
}
//Hold until all background workers complete
while (workerThreads.Count > m_CompletedWorkers)
{
Thread.Sleep(500); //Wait a half second
}
//Dispose of BackgroundWorkers
foreach (BackgroundWorker worker in workerThreads)
{
worker.Dispose();
}
//Get results
results.AddRange(m_MultithreadedEmailSendResults);
//Clear the static variable
m_MultithreadedEmailSendResults.Clear();
m_MultithreadedEmailSendResults = new List<EmailOutcome>();
return results;
}
...
/// <summary>
/// Event handler for the RunWorkerCompleted event. Adds the EmailOutcome results to the static
/// </summary>
private static void BulkEmailCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
//Add the EmailOutcome objects to the static list of results if completed
if (worker != null)
{
Thread.Sleep(200);
worker.RunWorkerAsync();
}
else
{
m_MultithreadedEmailSendResults.AddRange(e.Result as List<EmailOutcome>);
m_CompletedWorkers++;
}
}
...
}
...
}