获取ASP.NET MVC5的WebAPI令牌有时会失败 [英] Get ASP.NET MVC5 WebAPI token fails sometimes
问题描述
获取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(布尔
1.get_Result()
waitCompletionNotification)在
System.Threading.Tasks.Task
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.Task
1.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 .Result
s 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屋!