1

ASP.NET MVC4 Web ページから開始される長時間実行される非同期タスクがあります。コントローラ メソッドは次のようになります。

[HttpPost]
public ActionResult Index(IndexModel model)
{
    if (ModelState.IsValid)
    {
        try
        {
            model.NotificationRecipient = model.NotificationRecipient.Replace(';', ',');
            ImportConfiguration config = new ImportConfiguration()
            {
                BatchId = model.BatchId,
                ReportRecipients = model.NotificationRecipient.Split(',').Select(c => c.Trim())
            };
            System.Threading.ThreadPool.QueueUserWorkItem(foo => LaunchFileImporter(config, this.HttpContext.ApplicationInstance.Context));
            if (model.RunExport) ThreadPool.QueueUserWorkItem(foo => LaunchFileExporter());
            Log.InfoFormat("Queued the ImportProcessor to process invoices.  Send Notification: {0} Email Recipient: {1}",
                model.SendNotification, model.NotificationRecipient);
            TempData["message"] = "The import processor job has been started.";
            //return RedirectToAction("Index", "Home");
        }
        catch (Exception ex)
        {
            Log.Error("Failed to properly queue the invoice import job.", ex);
            ModelState.AddModelError("", ex.Message);
        }
    }

    var dirInfo = new System.IO.DirectoryInfo(dir);
    model.Files = dirInfo.EnumerateFiles("*.xml").OrderBy(x => x.Name.ToLower());

    return View(model);
}

私のLaunchFileImporter方法は次のようになります。

private void LaunchFileImporter(ImportConfiguration config, System.Web.HttpContext context)
{
    //the semaphore prevents concurrent running of this process, which can cause contention.
    Log.Trace(t => t("submitter semaphore: {0}", (exporter == null) ? "NULL" : "present."));
    submitter.WaitOne();
    try
    {
        Log.Trace(t => t("Context: {0}", context));
        using (var processor = new ImportProcessor(context))
        {
            processor.OnFileProcessed += new InvoiceFileProcessing(InvoiceFileProcessingHandler);
            processor.OnInvoiceProcessed += new InvoiceSubmitted(InvoiceSubmittedHandler);
            processor.Execute(config);
        }
    }
    catch (Exception ex)
    {
        Log.Error("Failed in execution of the File Importer.", ex);
    }
    submitter.Release();
}

私のロガーは Common.Loggingprivate static readonly ILogであり、NLog 用に構成されています。適切に配線されているようです。少なくとも、かなりの量のログが得られます。

これが問題です:私がヒットした瞬間System.Threading.ThreadPool.QueueUserWorkItem、アプリケーションプールの死は静かな死へと渦巻き、アプリプールをリセットし、メンバーシッププロバイダーをリロードし、web.configを再処理し、シバン全体を... YSODがなく、Webページに表示がありません...すべてが静かに爆発します。最後に取得したログ エントリはQueued the ImportProcessor to process invoices....

ページが更新されることに注意してください。が入力されて画面に表示されるTempData["message"]ので、非同期プロセスで問題が発生していると思われますが、ほとんどすぐに発生します。追加のログがないため、ロガーに問題があると推測しています。

だから私は、誰かが何が起こっているのかを教えてくれることを望んでいます.

ありがとう!

アップデート

@RichardDeeming は、生成されたスレッドにコンテキスト情報が入っていないことを指摘しており、これが問題の原因であると思われました。なぜこれがうまくいかなかったのか、トレースメッセージを書き込めなかったのか、まだ頭を悩ませていませんが、必要なコンテキストの一部をキャプチャしIPrincipal、コンテキストオブジェクトの代わりにそれを使用すると、うまくいきました.

4

1 に答える 1

3

NullReferenceException次の行が表示されます。

ThreadPool.QueueUserWorkItem(foo => LaunchFileImporter(config, HttpContext.ApplicationInstance.Context));

HttpContextリクエストが完了すると、 はクリーンアップされます。例外はバックグラウンド スレッドでスローされるため、全体がダウンし、AppDomainアプリケーションが再起動します。

コントローラー アクションのコンテキストから関連する状態をキャプチャし、WaitCallbackデリゲートでその状態を使用する必要があります。

IPrincipal user = Context.User;
ThreadPool.QueueUserWorkItem(foo => LaunchFileImporter(config, user));

// Or:
// ThreadPool.QueueUserWorkItem(state => LaunchFileImporter(config, (IPrincipal)state);
于 2012-12-10T21:50:37.220 に答える