我有这段代码来调用返回令牌的API。但是,仅当我替换以下行时,它才会返回:
var response = await TokenClient.PostAsync(EnvironmentHelper.TokenUrl, formContent);
有这行:
var response = TokenClient.PostAsync(EnvironmentHelper.TokenUrl, formContent).Result;
为什么?
public static async Task<Token> GetAPIToken()
{
if (DateTime.Now < Token.Expiry)
return Token;
TokenClient.DefaultRequestHeaders.Clear();
TokenClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
TokenClient.BaseAddress = new Uri(EnvironmentHelper.BaseUrl);
TokenClient.Timeout = TimeSpan.FromSeconds(3);
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", EnvironmentHelper.APITokenClientId),
new KeyValuePair<string, string>("client_secret", EnvironmentHelper.APITokenClientSecret)
});
try
{
// HANGS - this next line will only ever return if suffixed with '.Result'
var response = await TokenClient.PostAsync(EnvironmentHelper.TokenUrl, formContent);
var content = await response.Content.ReadAsStringAsync();
dynamic jsonContent = JsonConvert.DeserializeObject(content);
Token token = new Token();
token.AccessToken = jsonContent.access_token;
token.Type = jsonContent.token_type;
token.Expiry = DateTimeOffset.Now.AddSeconds(Convert.ToDouble(jsonContent.expires_in.ToString()) - 30);
token.Scope = Convert.ToString(jsonContent.scope).Split(' ');
Token = token;
}
catch (Exception ex)
{
var m = ex.Message;
}
return Token;
}
答案 0 :(得分:0)
未执行等待的最上面的代码是这样的:var wm = new WebRepo()。GetWeb(Id).Result
您遇到了deadlock since the synchronous code is blocking on async code。最好的解决方案是remove the blocking and go async all the way。
调用代码是带有getter的公共静态属性,在100多个地方引用了该代码。我不确定如何最好地将属性转换为异步友好
有a few approaches to async properties,具体取决于属性的语义。如果它在每次调用时都重新评估,那么它实际上是一种变相的方法,应成为async Task<T>
方法。如果设置一次,那么AsyncLazy<T>
可能是更好的选择。
有没有办法包装其中一个电话?重构那么多代码是一项艰巨的任务。
没有适用于所有情况的包装。但是,有些techniques for mixing sync and async code可以在特定情况下使用。
以下是我考虑的顺序:
GetAPIToken
(及其调用者)更改为同步而不是异步。 (要求所有调用代码都同步,这可能是不可能的。)GetAPIToken
可以同步和异步地被调用。 (需要具有更改GetAPIToken
的能力。)GetAPIToken
并同步阻止该线程上的另一个线程。