2016-08-17 3 views
0

Я пытаюсь получить токен доступа от Azure AD, и асинхронный вызов никогда не заканчивается. Я не уверен, что я делаю неправильно, может быть, кто-то может указать мне в правильном направлении. Это код:запустить асинхронный код из метода non async

private static void GetAccessTokenNonAsync() 
    { 
     Func<System.Threading.Tasks.Task> task = async() => { await GetAccessToken().ConfigureAwait(false); }; 
     task().Wait(); 
    } 
    private static async Task<AuthenticationResult> GetAccessToken() 
    { 
     string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"]; 
     string clientId = ConfigurationManager.AppSettings["ida:ClientId"]; 
     string clientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"]; 
     string source = ConfigurationManager.AppSettings["ExchangeOnlineId"]; 

     var authContext = new AuthenticationContext(aadInstance, false); 
     var credentials = new ClientCredential(clientId, clientSecret); 
     var appRedirectUrl = HttpContext.Current.GetOwinContext().Request.Scheme + "://" + HttpContext.Current.GetOwinContext().Request.Host + HttpContext.Current.GetOwinContext().Request.PathBase + "/"; 
     var res = 
      await 
       authContext.AcquireTokenByAuthorizationCodeAsync(
        ((ClaimsIdentity)HttpContext.Current.User.Identity).FindFirst("AuthenticationCode").Value, 
        new Uri(appRedirectUrl), credentials, source).ConfigureAwait(false); 
     Current.AccessToken = res.AccessToken; 
     return res; 

    } 
    private static string AccessToken 
    { 
     get 
     { 
      return HttpContext.Current.Session["AccessToken"].ToString(); 
     } 
     set { HttpContext.Current.Session["AccessToken"] = value; } 
    } 

И в моем основном методе, который я называю GetAccessTokenNonAsync()

+2

Возможный дубликат [Как я запустить Task асинхронной метод синхронно?] (http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously) – Igor

+1

@Igor: принятый ответ на этот вопрос имеет серьезные проблемы с возвращением. Пожалуйста, не рекомендуем. –

ответ

1

Вы используете асинхронное ключевое слово неправильно. Нечто подобное должно работать:

public static void GetAccessTokenNonAsync() 
{ 
    // Call the async method and get the resulting task. 
    Task<AuthenticationResult> accessTokenTask = GetAccessToken(); 
    // Wait for the task to finish. 
    accessTokenTask.Wait(); 
} 

private async static Task<AuthenticationResult> GetAccessToken() 
{ 
    return await Task.Factory.StartNew<AuthenticationResult> 
    (
     () => 
     { 
      // Insert code here. 
      return new AuthenticationResult(); 
     } 
    ); 
} 
0

Поскольку код асинхронный возвращает что-то (использует подпись Task), попробуйте сделать это, если вы нацелены последние рамки .net:

private static void GetAccessTokenNonAsync() 
{ 
    var result = GetAccessToken().ConfigureAwait(false).Result; 
} 
3

Вы бежите в deadlock scenario because you're blocking on async code , Я описываю детали своего блога.

В идеале вы не должны использовать HttpContext.Current в любом новом коде. Это довольно давно считается плохой практикой, и он полностью удален в ASP.NET Core (и не возвращается).

Похоже, что вы хотите сохранить токен в состоянии сеанса и (асинхронно) создать его, если необходимо. Соответствующий способ сделать это, чтобы сделать аксессора асинхронный:

public static async Task<string> GetAccessTokenAsync() 
{ 
    var result = HttpContext.Current.Session["AccessToken"] as string; 
    if (result != null) 
    return result; 

    ... 

    var res = await authContext.AcquireTokenByAuthorizationCodeAsync(...); 
    result = res.AccessToken.ToString(); 
    HttpContext.Current.Session["AccessToken"] = result; 
    return result; 
} 
+0

Я не думаю, что это решает мою проблему. Мне нужно восстановить токен доступа, когда пользователь должен его использовать, поэтому мне нужно, чтобы он был синхронным. Я также пользователь ConfigureAwait (false) для всех асинхронных вызовов, но он по-прежнему блокирует пользовательский интерфейс ... –

+0

@OanaMarina: Это не проблема; вы просто обновляете его асинхронно, а не синхронно. 'ConfigureAwait (false)' работает только в том случае, если вы используете его во всем стеке вызовов; возможно, что 'AcquireTokenByAuthorizationCodeAsync' не использует его. –

+0

Если я регенерирую его асинхронно, я не могу быть уверен, что он будет доступен в следующей строке кода, где я его использую. Мне нужно дождаться, когда он будет сгенерирован, а затем его использовать ... –

0

код, который наконец-то работал на это:

private static void GetAccessTokenNonAsync() 
    { 
     var userId = ((ClaimsIdentity)HttpContext.Current.User.Identity).FindFirst("UserId").Value; 

     var task = System.Threading.Tasks.Task.Run(async() => 
     { 
      return await GetAccessToken(userId); 
     }); 
     task.Wait(); 
     Current.AccessToken = task.Result.AccessToken; 
     Current.AccessTokenExpiresOn = task.Result.ExpiresOn.ToString(); 
    } 

    private static async Task<AuthenticationResult> GetAccessToken(string userId) 
    { 

     return await System.Threading.Tasks.Task.Factory.StartNew<AuthenticationResult> 
     (
      () => 
      { 
       string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"]; 
       string clientId = ConfigurationManager.AppSettings["ida:ClientId"]; 
       string clientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"]; 
       string source = ConfigurationManager.AppSettings["ExchangeOnlineId"]; 

       var authContext = new AuthenticationContext(aadInstance, false); 
       var credentials = new ClientCredential(clientId, clientSecret); 
       var res = 
        authContext.AcquireTokenSilentAsync(source, credentials, 
         new UserIdentifier(userId, UserIdentifierType.UniqueId)).Result; 
       return res; 
      } 
     ); 
    } 
Смежные вопросы