Use Task.Run instead of Delegate.BeginInvoke
asynchronous, c#
Solution
If I understood your requirements correctly, you want to kick off a task and then forget about it. When the task completes, and if an exception occurred, you want to log it.
I'd use `Task.Run` to create a task, followed by `ContinueWith` to attach a continuation task. This continuation task will log any exception that was thrown from the parent task. Also, use `TaskContinuationOptions.OnlyOnFaulted` to make sure the continuation only runs if an exception occurred.
Task.Run(() => {
var audit = new Audit
{
Id = Guid.NewGuid(),
IPAddress = request.UserHostAddress,
UserId = id,
Resource = request.RawUrl,
Timestamp = DateTime.UtcNow
};
var database = (new NinjectBinder()).Kernel.Get<IDatabaseWorker>();
database.Audits.InsertOrUpdate(audit);
database.Save();
}).ContinueWith(task => {
task.Exception.Handle(ex => {
var username = WebSecurity.CurrentUserName;
Debugging.DispatchExceptionEmail(ex, username);
});
}, TaskContinuationOptions.OnlyOnFaulted);
As a side-note, background tasks and fire-and-forget scenarios in ASP.NET are highly discouraged. See The Dangers of Implementing Recurring Background Tasks In ASP.NET
Problem
I have recently upgraded my projects to ASP.NET 4.5 and I have been waiting a long time to use 4.5's asynchronous capabilities. After reading the documentation I'm not sure whether I can improve my code at all. I want to execute a task asynchronously and then forget about it. The way that I'm currently doing this is by creating delegates and then using `BeginInvoke`. Here's one of the filters in my project with creates an audit in our database every time a user accesses a resource that must be audited: ``` public override void OnActionExecuting(ActionExecutingContext filterContext) { var request = filterContext.HttpContext.Request; var id = WebSecurity.CurrentUserId; var invoker = new MethodInvoker(delegate { var audit = new Audit { Id = Guid.NewGuid(), IPAddress = request.UserHostAddress, UserId = id, Resource = request.RawUrl, Timestamp = DateTime.UtcNow }; var database = (new NinjectBinder()).Kernel.Get<IDatabaseWorker>(); database.Audits.InsertOrUpdate(audit); database.Save(); }); invoker.BeginInvoke(StopAsynchronousMethod, invoker); base.OnActionExecuting(filterContext); } ``` But in order to finish this asynchronous task, I need to always define a callback, which looks like this: ``` public void StopAsynchronousMethod(IAsyncResult result) { var state = (MethodInvoker)result.AsyncState; try { state.EndInvoke(result); } catch (Exception e) { var username = WebSecurity.CurrentUserName; Debugging.DispatchExceptionEmail(e, username); } } ``` I would rather not use the callback at all due to the fact that I do not need a result from the task that I am invoking asynchronously. How can I improve this code with `Task.Run()` (or `async` and `await`)?