2015-04-28 26 views
0

在ASP Identity Framework 2中,UserManager爲其許多異步方法提供了同步包裝。遺憾的是此同步包裝使用AsyncHelper,說FindById(...):ASP Identity Framework 2:UserManager同步方法將運行在_other_線程中,使得HttpContext.Current爲空

return AsyncHelper.RunSync(() => manager.FindByIdAsync(userId)); 

審視RunSync方法原來它運行在其他線程的方法:

public static TResult RunSync<TResult>(Func<Task<TResult>> func) 
    { 
     var cultureUi = CultureInfo.CurrentUICulture; 
     var culture = CultureInfo.CurrentCulture; 
     return _myTaskFactory.StartNew(() => 
     { 
      Thread.CurrentThread.CurrentCulture = culture; 
      Thread.CurrentThread.CurrentUICulture = cultureUi; 
      return func(); 
     }).Unwrap().GetAwaiter().GetResult(); 
    } 

然而,在這種其他線程HttpContext.Current將爲空,因爲它是線程本地的。不幸的是,ASP身份框架2依賴於HttpContext.Current,例如種子的方法調用InitializeIdentityForEF,它試圖訪問這樣的背景下,並拋出一個空引用異常:

protected override void Seed(ApplicationDbContext context) 
    { 
     InitializeIdentityForEF(context); 
     base.Seed(context); 
    } 

    //Create [email protected] with [email protected] in the Admin role   
    // ReSharper disable once InconsistentNaming 
    public static void InitializeIdentityForEF(ApplicationDbContext db) 
    { 
     var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); 
     var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>(); 

我的主要問題:我怎樣才能調用UserManager的(或其他)異步方法,而不冒險編組到其他線程,其中HttpContext.Current將爲空,這可能會導致意外的行爲(在身份框架本身內)?顯然,提供的同步包裝是不可用的。

在有人問我爲什麼想要同步調用之前:假設我想在屬性get中使用UserManager,其中await不是一個選項。除此之外,同步包裝確實存在(出於我認爲的一個原因)僅僅不可用,或者至少引入了最糟糕的一種錯誤:在隨機地方隨機使用null。

+2

你不能使用'.Result'屬性嗎?像'manager.FindByIdAsync(userId).Result;'我認爲沒有必要爲這兩個塊創建一個任務,直到結果填充(如'AsyncHelper') –

+0

您是否真的試圖運行'Seed'方法'Global.asax.cs'? – trailmax

+0

trailmax:否請從下面的「Seed方法隱式運行...」開始閱讀我的意見。 –

回答

0

HttpContext.Current是線程安全的,可用於運行控制器操作的線程之外的線程。

我懷疑你正在運行你的Seed方法Application_Start異步操作不可用。也沒有HTTP請求,因爲應用程序啓動並且它不能接受請求。因此,您在HttpContext.Current中獲得null

爲了避免這個問題,您可以自己創建它們,而不是試圖從OwinContext獲取UserManager。創建所有依賴項並注入需要注入的所有內容。

+0

Seed方法隱式運行,不是我明確運行它的人。如果檢測到數據庫必須被創建並填充init數據,它纔會運行。不,我沒有從Application_Start運行它。它在我的HomeController中使用UserManager時運行(隱式)。然而,正如我之前所描述的,我使用的是使用AsyncHelper的FindById的同步版本,因此該方法將在另一個線程中運行,因此Seed將在另一個線程中運行。在這個線程中,HttpContext.Current爲null,(雖然它在那個線程中不是null,我稱之爲同步FindById。 –

+0

這很奇怪,因爲我可以在控制器中完全創建一個新線程,並仍然可以訪問'HttpContext.Current'。在你描述的相同場景下,同步方法對我來說沒有任何問題。 – trailmax

相關問題