簡體   English   中英

Web Api在異步方法上引發異常

[英]Web Api throwing Exception on async method

我有Web API方法,該方法調用另一個標記為用於更新數據庫的異步方法(使用EF 6)。 我不需要等待db方法完成(它觸發並忘記了),因此在調用此異步方法時不需要使用await 如果我不調用await ,則會拋出一個NullReferenceException,該異常永遠不會傳遞給我的代碼,而只會在VS2013的輸出窗口中顯示為第一次機會異常。

處理不await -a的異步方法的正確方法是什么?

以下是我在做什么的示例:

數據回購方法:

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存儲庫方法:

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方法:

 [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);
    }

最后我得到的堆棧跟蹤:

    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()

編輯:我已經更改了我的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
        };

    }

我不需要等待db方法完成(它觸發並忘記了)

當我看到此消息時,我總是做的第一件事是問:您絕對確定要這樣做嗎?

請記住,ASP.NET上的“解雇”實際上就是說“我不在乎此代碼是否真正執行過”。

由於您只是在更新“最后檢查”時間,因此您可能想要的就是一勞永逸。 請注意,這意味着您的上次檢查時間可能正確或可能不正確。

就是說,您可以按照我在博客中所描述的那樣在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
  };
}

請注意,這是假設UpdateSessionCheckAsync確實返回Task

尤其是:

  • async void方法具有非常尷尬的錯誤處理語義。 如果在寫入數據庫時​​遇到問題,則默認情況下, async void方法將使您的應用程序崩潰。
  • 正如我在博客中所解釋的, Task.Factory.StartNew非常危險

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM