I have Web API method that calls another method marked with async used to update a database (using EF 6). I do not need to wait on the db method to complete (its fire and forget), hence I do not use await
when calling this async method. If I do not call await
, a NullReferenceException is thrown that is never passed to my code, and just shows up as a first chance exception in the output window of VS2013.
What is the proper way to handle calling an async method without await
-ing?
Below is an example of what I am doing:
data repo method:
public async Task UpdateSessionCheckAsync(int sessionId, DateTime time)
{
using (MyEntities context = new MyEntities())
{
var session = await context.Sessions.FindAsync(sessionId);
if (session != null)
session.LastCheck = time;
await context.SaveChangesAsync();
}
}
Web api repository method:
public async Task<ISession> GetSessionInfoAsync(int accountId, int siteId, int visitorId, int sessionId)
{
//some type of validation
var session =await GetValidSession(accountId, siteId, visitorId, sessionId);
DataAdapter.UpdateSessionCheckAsync(sessionId, DateTime.UtcNow); // this is the line causing the exception if not awaited
return new Session
{
Id = sessionId,
VisitorId = session.VisitorId
};
}
Web API Method:
[ResponseType(typeof(Session))]
public async Task<IHttpActionResult> GetSessionInfo(HttpRequestMessage request, int accountId, int siteId, int visitorId, int sessionId)
{
var info = await _repository.GetSessionInfoAsync(accountId, siteId, visitorId, sessionId);
return Ok(info);
}
and finally the stack trace I get:
System.Web.dll!System.Web.ThreadContext.AssociateWithCurrentThread(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.OnThreadEnterPrivate(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
System.Web.dll!System.Web.Util.SynchronizationHelper.SafeWrapCallback(System.Action action)
System.Web.dll!System.Web.Util.SynchronizationHelper.QueueAsynchronous.AnonymousMethod__7(System.Threading.Tasks.Task _)
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
edit: Ive changed my db method to return void instead of task, and then used Task.Factory to start a new task calling the db method and the exception is gone.
public async Task<ISession> GetSessionInfoAsync(int accountId, int siteId, int visitorId, int sessionId)
{
//some type of validation
var session =await GetValidSession(accountId, siteId, visitorId, sessionId);
Task.Factory.StartNew(() => DataAdapter.UpdateSessionCheckAsync(sessionId, DateTime.UtcNow));
return new Session
{
Id = sessionId,
VisitorId = session.VisitorId
};
}