C# 异步函数在WebMethod中会死锁,但在Page_Load中调用时效果良好
我有一个WebForms项目,它试图利用一些C# 异步函数在WebMethod中会死锁,但在Page_Load中调用时效果良好,c#,asynchronous,webforms,webmethod,C#,Asynchronous,Webforms,Webmethod,我有一个WebForms项目,它试图利用一些async代码。在早期开发过程中,我只是在页面加载中调用我的异步代码(这也是异步),并将结果写入响应。很好,易于测试。一切如期进行 代码可以总结为: 获取Azure授权令牌 向Azure的REST API发出HTTP请求 将结果返回给客户端 因此,当我试图在WebMethod中调用这个async方法时,我感到非常惊讶,但失败了。它似乎在其他async代码(特别是Azure AD方法)上处于死锁状态 我的第一个想法是一些上下文魔法,但是Configure
async
代码。在早期开发过程中,我只是在页面加载
中调用我的异步
代码(这也是异步
),并将结果写入响应
。很好,易于测试。一切如期进行
代码可以总结为:
WebMethod
中调用这个async
方法时,我感到非常惊讶,但失败了。它似乎在其他async
代码(特别是Azure AD方法)上处于死锁状态
我的第一个想法是一些上下文魔法,但是ConfigureAwait(false)
没有任何效果。所以我完全不知道有什么不同。我尝试过WebMethod
是async
还是非的方法,结果没有差别。快速测试表明,这种WebMethod
的配置方式没有任何问题——让我的代码尽早返回(在调用AD代码之前)可以让它按预期工作。尽管那时没有发生任何异步事件
我还尝试使用非异步方法获取Azure AD令牌。这可以正常工作,但是当我的应用程序尝试发出HTTP请求时(使用RestSharp.Portable库,它只提供async
方法),它就会卡住。我的代码如下所示:
protected async Task<JObject> PerformRequest(string path, Method method, string apiVersion, string requestBody)
{
RestClient client = new RestClient("https://management.azure.com");
RestRequest request = new RestRequest(path, method);
request.AddParameter("api-version", apiVersion);
request.AddHeader("Authorization", await this.GetAccessTokenAsync());
IRestResponse<JObject> response = await client.Execute<JObject>(request);
return response.Data;
}
public async Task<string> GetAccessTokenAsync()
{
string tenantId = "xxx";
AuthenticationContext authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}");
ClientCredential credential = new ClientCredential(clientId: "xxx", clientSecret: "xxx=");
AuthenticationResult result = await authenticationContext.AcquireTokenAsync(resource: "https://management.core.windows.net/", clientCredential: credential);
if (result == null) throw new InvalidOperationException("Failed to obtain the JWT token");
return this.accessToken = result.AccessTokenType + " " + result.AccessToken;
}
对所有这些的调用都直接在WebMethod
中进行(这是WebMethod
目前唯一做的事情):
为什么我的应用程序在WebMethod
中调用此代码而不是在Page\u Load
中调用此代码时会出现此问题?我能做些什么来解决这个问题?更改您的
IRestResponse<JObject> response = await client.Execute<JObject>(request);
IRestResponse response=wait client.Execute(请求);
到
IRestResponse response=wait client.Execute(请求)。configurewait(false);
这对你有帮助吗?
问题是两个“wait”都在等待同时捕获相同的上下文,ConfigureWait阻止此操作(读取其文档)我们可以看到您在哪里调用PerformRequest
?您是否在任何地方等待调用PerformRequest
的结果?是否可以将代码发布到此.GetAccessToken?另外,请您使用HTTP嗅探器(如fiddler)发布运行此代码的结果。@Aron,我已为GetAccessToken
添加了代码。这与MDSN演示的内容几乎相同。@spender,我已将此添加到问题中。听起来您是在建议两个内部任务同时运行。但我认为它应该按顺序运行,不应该“同时”发生。请注意,异步/等待模式是一个陷阱是的。但正是与Task.Result的交互导致了问题。OP正在运行“一路异步”。不,这没有什么区别。我不明白为什么会这样,因为这两个等待应该是连续的(必须在发出请求之前设置身份验证头)。无论如何,试图改变不会导致任何变化。它似乎也没有解释为什么这会“正常”工作,但不适用于WebMethod
。
IRestResponse<JObject> response = await client.Execute<JObject>(request);
IRestResponse<JObject> response = await client.Execute<JObject>(request).ConfigureAwait(false);