Прежде всего, я использую ASP.NET 4.0. Затем я обернул IRegisteredObject внутри BackgroundWorker соответствующим блоком try/catch.
public class BackgroundWorker
{
/// <summary>
/// Runs a background task that is registered with the hosting environment
/// so it is guaranteed to finish executing.
/// </summary>
/// <param name="action">The lambda expression to invoke.</param>
public static void Run(Action action)
{
new IISBackgroundTask().DoWork(action);
}
/// <summary>
/// Generic object for completing tasks in a background thread
/// when the request doesn't need to wait for the results
/// in the response.
/// </summary>
class IISBackgroundTask : IRegisteredObject
{
/// <summary>
/// Constructs the object and registers itself with the hosting environment.
/// </summary>
public IISBackgroundTask()
{
HostingEnvironment.RegisterObject(this);
}
/// <summary>
/// Called by IIS, once with <paramref name="immediate"/> set to false
/// and then again with <paramref name="immediate"/> set to true.
/// </summary>
void IRegisteredObject.Stop(bool immediate)
{
if (_task.IsCompleted || _task.IsCanceled || _task.IsFaulted || immediate)
{
// Task has completed or was asked to stop immediately,
// so tell the hosting environment that all work is done.
HostingEnvironment.UnregisterObject(this);
}
}
/// <summary>
/// Invokes the <paramref name="action"/> as a Task.
/// Any exceptions are logged
/// </summary>
/// <param name="action">The lambda expression to invoke.</param>
public void DoWork(Action action)
{
try
{
_task = Task.Factory.StartNew(action);
}
catch (AggregateException ex)
{
// Log exceptions
foreach (var innerEx in ex.InnerExceptions)
{
Logger.Log(innerEx);
}
}
catch (Exception ex)
{
Logger.Log(ex);
}
}
private Task _task;
private static readonly ILogger Logger = Loggers.Logger.Instance;
}
}
и я называю это,
BackgroundWorker.Run(() =>
// My Code
);
Но мой процесс asp.net иногда падает.
Faulting application name: w3wp.exe, version: 7.5.7601.17514, time stamp: 0x4ce7afa2
Faulting module name: KERNELBASE.dll, version: 6.1.7601.17514, time stamp: 0x4ce7c78c
Exception code: 0xe0434352
Fault offset: 0x000000000000a49d
Faulting process id: 0x2b90
Faulting application start time: 0x01cfb515a14c3320
Faulting application path: c:\windows\system32\inetsrv\w3wp.exe
Faulting module path: C:\Windows\system32\KERNELBASE.dll
Report Id: 9f0a3510-2164-11e4-822a-4040610959cf
Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AggregateException
Stack:
at System.Threading.Tasks.TaskExceptionHolder.Finalize()
An unhandled exception occurred and the process was terminated.
Application ID: /LM/W3SVC/2/ROOT
Process ID: 11152
Exception: System.AggregateException
Message: A Task exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
StackTrace: at System.Threading.Tasks.TaskExceptionHolder.Finalize()
InnerException: System.XXXX
Message: XXXX
StackTrace:
at MyMethod
at System.Threading.Tasks.Task.Execute()
Ну, вы начинаете выполнять свою Task
внутри DoWork
используя Task.Factory.Startnew
, но затем DoWork
завершает выполнение, поскольку он не ожидает использования await
или не обрабатывает никаких исключений с использованием продолжения, что означает catch (AggregateException e)
довольно бесполезно.
Вы должны зарегистрировать продолжение, используя ContinueWith
:
public void DoWork(Action action)
{
_task = Task.Factory.StartNew(action).ContinueWith((previousTask) =>
{
foreach (var innerEx in ex.InnerExceptions)
{
Logger.Log(innerEx);
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
async
/await
не следует использовать в ASP.NET 4.0, но ваше второе решение хорошо.async-await
ASP.NET 4, не могли бы вы подробнее рассказать, почему его не следует использовать? Это из-за маршалинга контекста запроса сLegacyAspNetSynchronizationContext
?