2016-04-29 24 views
1

は、ASP.NET MVC5 WebAPIのトークンを取得しますゲットASP.NET MVC5 WebAPIのトークンは時々

1つ以上のエラーが発生した

コード

string GetAPITokenSync(string username, string password, string apiBaseUri) 
     { 
      var token = string.Empty; 

      using (var client = new HttpClient()) 
      { 
       client.BaseAddress = new Uri(apiBaseUri); 
       client.DefaultRequestHeaders.Accept.Clear(); 
       client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
       client.Timeout = TimeSpan.FromSeconds(60); 

       //setup login data 
       var formContent = new FormUrlEncodedContent(new[] 
       { 
       new KeyValuePair<string, string>("grant_type", "password"), 
       new KeyValuePair<string, string>("username", username), 
       new KeyValuePair<string, string>("password", password), 
       }); 

       //send request    
       Task t = Task.Run(() => 
       { 
        HttpResponseMessage responseMessage = client.PostAsync("/Token", formContent).Result; 
        var responseJson = responseMessage.Content.ReadAsStringAsync().Result; 
        var jObject = JObject.Parse(responseJson); 
        token = jObject.GetValue("access_token").ToString(); 
       }); 

       t.Wait(); 
       t.Dispose(); 
       t = null; 
       GC.Collect(); 

       return token; 
      } 
     } 

エラー時には失敗失敗しました。 ---> System.AggregateException:1つまたは エラーが発生しました。 ---> System.Threading.Tasks.TaskCanceledException:タスクがキャンセルされました。 System.Threading.Tasks.Task 1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task 1.get_Result()


---内部例外スタックトレースの終わり--- System.Threading.Tasks.Task.ThrowIfExceptionalで(ブール includeTaskCanceled例外)

WebAPiログインメソッドはデフォルトで変更されていません。

[HttpPost] 
[AllowAnonymous] 
[Route("Login")] 
public HttpResponseMessage Login(string username, string password) 
    { 
     try 
     { 
      var identityUser = UserManager.Find(username, password); 

      if (identityUser != null) 
      { 
       var identity = new ClaimsIdentity(Startup.OAuthOptions.AuthenticationType); 
       identity.AddClaim(new Claim(ClaimTypes.Name, username)); 

       AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties()); 
       var currentUtc = new SystemClock().UtcNow; 
       ticket.Properties.IssuedUtc = currentUtc; 
       ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(1440)); 

       var token = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket); 

       var response = new HttpResponseMessage(HttpStatusCode.OK) 
       { 
        Content = new ObjectContent<object>(new 
        { 
         UserName = username, 
         ExternalAccessToken = token 
        }, Configuration.Formatters.JsonFormatter) 
       }; 

       return response; 


      } 
     } 
     catch (Exception) 
     { 
     } 

     return new HttpResponseMessage(HttpStatusCode.BadRequest); 
    } 
} 

スタートアップクラスには

public partial class Startup 
    { 
     public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } 

     public static string PublicClientId { get; private set; } 


     public void ConfigureAuth(IAppBuilder app) 
     { 
      // Configure the db context and user manager to use a single instance per request 
      app.CreatePerOwinContext(ApplicationDbContext.Create); 
      app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

      // Enable the application to use a cookie to store information for the signed in user 
      // and to use a cookie to temporarily store information about a user logging in with a third party login provider 
      app.UseCookieAuthentication(new CookieAuthenticationOptions()); 
      app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 

      // Configure the application for OAuth based flow 
      PublicClientId = "self"; 
      OAuthOptions = new OAuthAuthorizationServerOptions 
      { 
       TokenEndpointPath = new PathString("/Token"), 
       Provider = new ApplicationOAuthProvider(PublicClientId), 
       AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), 
       AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), 
       // In production mode set AllowInsecureHttp = false 
       AllowInsecureHttp = true 
      }; 

      // Enable the application to use bearer tokens to authenticate users 
      app.UseOAuthBearerTokens(OAuthOptions); 
     } 
    } 

任意の手掛かりを変更し、デフォルトではないのですか?

+1

は、それがタイムアウトしませんか? 60秒後に?なぜあなたはタスクで投稿を実行していますか?その後、タスクが終了するのを待つ呼び出しスレッドをブロックしますか? –

+0

@BrunoGarcia私はトークンを取得するには60秒はOKだと思います。考慮すべきことをアドバイスしてください...ありがとう! –

+0

私の場合:あなたの呼び出しがタイムアウトしているので問題はありませんか?サーバーに到達できないか、または完了に時間がかかりすぎる(60秒以上)ためですか?特に失敗する場合があります –

答えて

6

確かに言うことは難しいですが、HttpClientの呼び出しをブロックしている方法では手助けできません。 HttpClientは非同期専用ライブラリです。あなたはデッドロック状況があるかもしれません。 .Result.Wait()をすべて削除し、すべてを非同期で書き込むことをお勧めします。async/awaitを使用してください。あなたのTask.Runは何も達成していないので、それは行かなければなりません。

これは、コンソールアプリから移植されたTopshelfアプリです。私はTopshelfについてあまりよく知らないが、コンソールアプリケーションのように、のどこかでをブロックする必要があると思う。それを行う場所はアプリのエントリーポイントの一番上にあります。

これはあなたのGetApiToken方法の再書き込みと一緒に、パターンを示しています

// app entry point - the only place you should block 
void Main() 
{ 
    MainAsync().Wait(); 
} 

// the "real" starting point of your app logic. do everything async from here on 
async Task MainAsync() 
{ 
    ... 
    var token = await GetApiTokenAsync(username, password, apiBaseUri); 
    ... 
} 

async Task<string> GetApiTokenAsync(string username, string password, string apiBaseUri) 
{ 
    var token = string.Empty; 

    using (var client = new HttpClient()) 
    { 
     client.BaseAddress = new Uri(apiBaseUri); 
     client.DefaultRequestHeaders.Accept.Clear(); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
     client.Timeout = TimeSpan.FromSeconds(60); 

     //setup login data 
     var formContent = new FormUrlEncodedContent(new[] 
     { 
     new KeyValuePair<string, string>("grant_type", "password"), 
     new KeyValuePair<string, string>("username", username), 
     new KeyValuePair<string, string>("password", password), 
     }); 

     //send request    
     HttpResponseMessage responseMessage = await client.PostAsync("/Token", formContent); 
     var responseJson = await responseMessage.Content.ReadAsStringAsync(); 
     var jObject = JObject.Parse(responseJson); 
     token = jObject.GetValue("access_token").ToString(); 

     return token; 
    } 
} 
関連する問題