2016-04-29 2 views
1

Получить ASP.NET MVC5 WebAPI маркер проваливается иногдаПолучить ASP.NET MVC5 WebAPI маркер не удается иногда

Код

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: Один или произошло больше ошибок. ---> System.Threading.Tasks.TaskCanceledException: задача была отменена.
--- Конец внутренней трассировки стека исключений --- в System.Threading.Tasks.Task.ThrowIfExceptional (Boolean includeTaskCanceled Исключения) при System.Threading.Tasks.Task 1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task 1.get_Result()

Метод входа в 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 секунд в порядке, чтобы получить токен. Пожалуйста, советьте что-то рассмотреть ... Спасибо! –

+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; 
    } 
} 
Смежные вопросы