获取ASP.NET MVC5的WebAPI令牌有时会失败 [英] Get ASP.NET MVC5 WebAPI token fails sometimes

查看:1306
本文介绍了获取ASP.NET MVC5的WebAPI令牌有时会失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

获取ASP.NET MVC5的WebAPI令牌有时会失败

Get ASP.NET MVC5 WebAPI token fails sometimes

code

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(布尔
  includeTaskCanceled例外情况)
  System.Threading.Tasks.Task 1.GetResultCore(布尔
  waitCompletionNotification)在
  System.Threading.Tasks.Task
1.get_Result()

One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
--- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceled Exceptions) at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task1.get_Result()

的WebAPI的登录方法是在默认情况下没有变化。

WebAPi login method is by default has no changes.

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

启动类是在默认情况下没有改变。

Startup class is by default no changes

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

任何线索?

推荐答案

这很难肯定地说,但你挡住HttpClient的方式调用不能帮助。 HttpClient的是一个只有异步库;你可能有一个死锁的情况。我建议摆脱所有。结果 .Wait 和使用异步写的一切,()异步/的await 。和你的Task.Run是四大皆空,让该走了。

It's hard to say for certain, but the way you're blocking HttpClient calls can't be helping. HttpClient is an async-only library; you may have a deadlock situation. I suggest getting rid of all .Results and .Wait()s and write everything asynchronously, using async/await. And your Task.Run is achieving nothing, so that should go.

我明白这是一个控制台应用程序移植了Topshelf应用程序。我不是很熟悉Topshelf,但我认为,像控制台应用程序,你需要阻止的地方的或您的应用程序将简单地退出。做到这一点的地方是在最高层 - 应用程序的入口点

I understand this is Topshelf app ported over from a console app. I'm not very familiar with Topshelf, but I assume that, like console apps, you need to block somewhere or your app will simply exit. The place to do that is at the very top - the entry point of the app.

此演示模式,用一个重新写沿着你的 GetApiToken 方法:

This demonstrates the pattern, along with a re-write of your GetApiToken method:

// 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;
    }
}

这篇关于获取ASP.NET MVC5的WebAPI令牌有时会失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆