Mik*_*e_G 1 c# async-await asp.net-web-api
我有Web API方法调用另一个标记为async的方法来更新数据库(使用EF 6).我不需要等待db方法来完成(它的火和忘记),因此我await在调用这个异步方法时不会使用它.如果我不调用await,则抛出NullReferenceException,它永远不会传递给我的代码,只是在VS2013的输出窗口中显示为第一次机会异常.
没有await-ing 处理异步方法的正确方法是什么?
以下是我正在做的事情的一个例子:
数据回购方法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Web api存储库方法:
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
};
}
Run Code Online (Sandbox Code Playgroud)
Web API方法:
[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);
}
Run Code Online (Sandbox Code Playgroud)
最后得到的堆栈跟踪:
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()
Run Code Online (Sandbox Code Playgroud)
编辑: 我已经改变了我的db方法返回void而不是task,然后使用Task.Factory启动一个调用db方法的新任务,异常就消失了.
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
};
}
Run Code Online (Sandbox Code Playgroud)
我不需要等待db方法来完成(它的火和忘记)
当我看到这一点时,我总是会做的第一件事是:你绝对确定要这样做吗?
请记住,ASP.NET上的"fire and forget"与"我不关心这段代码是否真的被执行"完全相同.
由于您只是更新了"最后检查"时间,因此您可能会想到"即发即忘"; 请注意,这意味着您的上次检查时间实际上可能正确也可能不正确.
也就是说,您可以像我在博客中描述的那样在ASP.NET运行时注册您的工作:
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);
BackgroundTaskManager.Run(() => DataAdapter.UpdateSessionCheckAsync(sessionId, DateTime.UtcNow));
return new Session
{
Id = sessionId,
VisitorId = session.VisitorId
};
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是假设UpdateSessionCheckAsync确实返回a Task.
特别是:
async void方法具有非常笨拙的错误处理语义.如果写入数据库时出现问题async void,默认情况下,某个方法会使应用程序崩溃.Task.Factory.StartNew我正在博客上解释,这是相当危险的.| 归档时间: |
|
| 查看次数: |
2905 次 |
| 最近记录: |