【发布时间】:2019-11-17 13:35:28
【问题描述】:
我有一个创建函数的包装器 已创建公共异步任务 getCacheToken 供一些内部服务/应用程序调用
我在另一个服务中调用 performExtract() 时遇到了这个异常(请参见下文)。
performExtract 实际上是通过 API 调用调用 getCacheToken
我忍不住在同步方法(旧环境)中发送异步调用,所以每次我在循环中调用 var results = client.SendAsync(requestData).Result' 时都会导致死锁, 如果我理解正确,sendAsync 在 for 循环中,它会在开始另一个任务之前等待一个任务完成,所以它不应该有以下异常(连接已处理?)
要修复它,我必须重写 send Async ConfigureAwait(false),它解决了我的问题。
我的问题是如何添加 ConfigureAwait(false) 解决问题?
为避免此问题,您可以使用带有 false 参数的 ConfigureAwait 方法。当你这样做时,这告诉任务它可以在任何可用的线程上恢复自己,而不是等待最初创建它的线程。这将加快响应速度并避免许多死锁。
以及如何异步运行它会导致死锁?
非常感谢您通过帖子阅读的所有耐心。
protected override ExtractResultStatus PerformExtract()
{
//EngageRestClient client = new EngageRestClient(_apiEndPoint);
//client.Authenticator = new NtlmAuthenticator();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
try
{
var numErrors = 0;
var dt = GetInfos();
var fileName = string.Format(FilenameBase, DateTime.Now);
if (dt.Rows.Count > 0)
{
dt.Columns.Add("failureReason");
foreach (DataRow row in dt.Rows)
{
var referenceID = row["U3l_ReferenceId"].ToString();
var requestData = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_apiEndPoint + $"?referenceID={referenceID}"),
};
requestData.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
var results = client.SendAsync(requestData).Result;
var resultResponse = results.Content.ReadAsStringAsync().Result;
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
for (int i = 0; i < MaxRetries; i++)
{
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
if (response.StatusCode != HttpStatusCode.InternalServerError ||
response.StatusCode != HttpStatusCode.NotImplemented ||
response.StatusCode != HttpStatusCode.GatewayTimeout ||
response.StatusCode != HttpStatusCode.ServiceUnavailable)
{
return response;
}
response.Dispose();
}
return response;
}
public async Task<string> GetCacheToken()
{
ObjectCache cache = MemoryCache.Default;
string refreshToken = cache.Get("refreshToken", null) == null ? GetToken() : cache.Get("refreshToken", null).ToString();
if (!cache.Contains("apiToken"))
{
var httpContent = new StringContent("", Encoding.UTF8, "application/x-www-form-urlencoded");
var dict = new Dictionary<string, string>();
dict.Add("grant_type", "refresh_token");
dict.Add("refresh_token", refreshToken);
var requestData = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://oauth2.sky.blackbaud.com/token"),
Content = new FormUrlEncodedContent(dict)
};
requestData.Headers.Authorization = new AuthenticationHeaderValue("Basic", Settings.BasicAuth);
var results = await _client.SendAsync(requestData);
var resultResponse = results.Content.ReadAsStringAsync().Result;
try
{
results.EnsureSuccessStatusCode();
var result = _js.Deserialize<TokenModel>(resultResponse);
//token expires in one hour from blackbaud
var expiration = DateTimeOffset.UtcNow.AddMinutes(55);
cache.Add("apiToken", result.access_token, expiration);
cache.Add("refreshToken", result.refresh_token, expiration);
UpdateToken(result.access_token, result.refresh_token);
}
catch (Exception e)
{
var exceptionMessage = $"ResultMessage : {resultResponse} Exception: {e}. Message: {e.Message}. Stacktrace {e.StackTrace}";
Log.Exception(e,exceptionMessage);
throw;
}
}
return cache.Get("apiToken", null).ToString();
}
{Data: [], HResult: -2146233088, HelpLink: null, InnerException: null, 消息:“响应状态码不表示成功:400(错误 请求)。”,来源:“System.Net.Http”,StackTrace:“在 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()\r\n at RaisersEdge.Infrastructure.Cache.d__2.MoveNext()\r\n--- 从先前抛出异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\r\n 在 RaisersEdge.Controllers.BaseController.d__6.MoveNext()\r\n--- 从先前抛出异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\r\n 在 System.Threading.Tasks.TaskHelpersExtensions.d__3`1.MoveNext()\r\n--- 从先前抛出异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\r\n 在 System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n--- 从先前抛出异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\r\n 在 System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n--- 从先前抛出异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()", 目标站点:“System.Net.Http.HttpResponseMessage EnsureSuccessStatusCode()", _typeTag: "HttpRequestException"}
【问题讨论】:
-
看到这个
.Result了吗?不要这样做......永远......除非你确切地知道你在做什么。它可能会导致您正在寻找的死锁。 -
其中一项服务位于旧环境中,无法调用 await,因为我没有要覆盖的异步函数
标签: c#