C# HttpClient-任务已取消?
当有一个或两个任务时,它可以正常工作,但是当我们列出了多个任务时,它会抛出一个错误“任务被取消”C# HttpClient-任务已取消?,c#,task-parallel-library,dotnet-httpclient,C#,Task Parallel Library,Dotnet Httpclient,当有一个或两个任务时,它可以正常工作,但是当我们列出了多个任务时,它会抛出一个错误“任务被取消” List<Task> allTasks = new List<Task>(); allTasks.Add(....); allTasks.Add(....); Task.WaitAll(allTasks.ToArray(), configuration.CancellationToken); private static Task<T> HttpClientS
List<Task> allTasks = new List<Task>();
allTasks.Add(....);
allTasks.Add(....);
Task.WaitAll(allTasks.ToArray(), configuration.CancellationToken);
private static Task<T> HttpClientSendAsync<T>(string url, object data, HttpMethod method, string contentType, CancellationToken token)
{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url);
HttpClient httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(Constants.TimeOut);
if (data != null)
{
byte[] byteArray = Encoding.ASCII.GetBytes(Helper.ToJSON(data));
MemoryStream memoryStream = new MemoryStream(byteArray);
httpRequestMessage.Content = new StringContent(new StreamReader(memoryStream).ReadToEnd(), Encoding.UTF8, contentType);
}
return httpClient.SendAsync(httpRequestMessage).ContinueWith(task =>
{
var response = task.Result;
return response.Content.ReadAsStringAsync().ContinueWith(stringTask =>
{
var json = stringTask.Result;
return Helper.FromJSON<T>(json);
});
}).Unwrap();
}
List allTasks=new List();
所有任务。添加(…);
所有任务。添加(…);
Task.WaitAll(allTasks.ToArray(),configuration.CancellationToken);
私有静态任务HttpClientSendAsync(字符串url、对象数据、HttpMethod方法、字符串contentType、CancellationToken令牌)
{
HttpRequestMessage HttpRequestMessage=新的HttpRequestMessage(方法,url);
HttpClient HttpClient=新HttpClient();
httpClient.Timeout=新的时间跨度(常数.Timeout);
如果(数据!=null)
{
byte[]byteArray=Encoding.ASCII.GetBytes(Helper.ToJSON(data));
MemoryStream MemoryStream=新的MemoryStream(byteArray);
httpRequestMessage.Content=新的StringContent(新的StreamReader(memoryStream).ReadToEnd(),Encoding.UTF8,contentType);
}
返回httpClient.SendAsync(httpRequestMessage).ContinueWith(任务=>
{
var response=task.Result;
返回response.Content.ReadAsStringAsync().ContinueWith(stringTask=>
{
var json=stringTask.Result;
返回Helper.FromJSON(json);
});
}).Unwrap();
}
引发TaskCanceledException
的原因可能有两个:
CancellationTokenSource
上名为Cancel()
的内容HttpClient.Timeout
上指定的时间范围内完成try
{
var response = task.Result;
}
catch (TaskCanceledException ex)
{
// Check ex.CancellationToken.IsCancellationRequested here.
// If false, it's pretty safe to assume it was a timeout.
}
我遇到这个问题是因为我的
Main()
方法在返回之前没有等待任务完成,所以当我的控制台程序退出时,task myTask
被取消
#≥ 7.1
你可以继续等待任务
公共静态异步任务Main(){
Task myTask=sendRequest();//创建任务的方式
HttpResponseMessage response=等待我的任务;
//处理响应
}
C#<7.1
解决方案是在
Main()
(from)中调用myTask.GetAwaiter().GetResult()
。另一种可能是客户端不等待结果。如果调用堆栈上的任何一个方法没有使用wait关键字来等待调用完成,则可能会发生这种情况。另一个原因可能是,如果您正在运行服务(API)并在服务中放置断点(并且您的代码卡在某个断点处)(例如,Visual Studio解决方案显示调试而不是运行)。然后从客户端代码中点击API。因此,如果服务代码a在某个断点上暂停,您只需点击VS中的F5
var clientHttp = new HttpClient();
clientHttp.Timeout = TimeSpan.FromMinutes(30);
以上是等待大型请求的最佳方法。
你对30分钟感到困惑;这是随机时间,你可以给任何你想要的时间
换句话说,如果在30分钟之前得到结果,请求将不会等待30分钟。
30分钟表示请求处理时间为30分钟。
当出现错误“任务被取消”或大数据请求要求时。在我的情况下,控制器方法不是异步的,控制器方法内部调用的方法是异步的
因此,我想使用async/Wait一直到顶层是很重要的,以避免类似的问题。在我的.net core 3.1应用程序中,我遇到了两个问题,其内在原因是超时异常。 1,一个是我得到聚合异常,它的内部异常是超时异常 2、其他情况为任务取消异常 我的解决办法是
catch (Exception ex)
{
if (ex.InnerException is TimeoutException)
{
ex = ex.InnerException;
}
else if (ex is TaskCanceledException)
{
if ((ex as TaskCanceledException).CancellationToken == null || (ex as TaskCanceledException).CancellationToken.IsCancellationRequested == false)
{
ex = new TimeoutException("Timeout occurred");
}
}
Logger.Fatal(string.Format("Exception at calling {0} :{1}", url, ex.Message), ex);
}
我使用了一个简单的调用,而不是
async
。当我添加wait
并使方法async
时,它就开始正常工作了
public async Task<T> ExecuteScalarAsync<T>(string query, object parameter = null, CommandType commandType = CommandType.Text) where T : IConvertible
{
using (IDbConnection db = new SqlConnection(_con))
{
return await db.ExecuteScalarAsync<T>(query, parameter, null, null, commandType);
}
}
公共异步任务ExecuteScalarAsync(字符串查询,对象参数=null,CommandType CommandType=CommandType.Text),其中T:IConvertible
{
使用(IDbConnection db=newSQLConnection(_con))
{
返回wait db.ExecuteScalarAsync(查询,参数,null,null,commandType);
}
}
将@JobaDiniz的评论升级为答案: 不要做显而易见的事情并处理
HttpClient
实例,即使代码“看起来正确”:
异步任务方法(){
使用(var client=new HttpClient())
返回client.GetAsync(请求);
}
C#的新RIAA语法也是如此;稍微不那么明显:
异步任务方法(){
使用var client=new HttpClient();
返回client.GetAsync(请求);
}
相反,请为您的应用程序或库缓存
HttpClient
的静态实例,并重新使用它:
statichttpclient=newhttpclient();
异步任务方法(){
返回client.GetAsync(请求);
}
(Async()请求方法。)内部异常说明了什么?为什么将
CancellationToken
作为参数而不使用它?我的原因是错误地处理HttpClient
,例如Async任务方法(){using(var client=new HttpClient())return client.GetAsync(request);}
对于那些使用HttpClient
的人,比如@JobaDiniz(使用using()
),请停止!原因:那么可能的解决方案是什么呢?我有一个类似的问题。@Dimi-这很旧,但我使用的解决方案是将Timeout属性设置为更大的值:HttpClient.Timeout=TimeSpan.FromMinutes(30)
@RQDQ,你就是那个人,伙计!不使用构造函数为我解决了问题。在我的特定情况下,我想要一个以毫秒为单位的超时。使用TimeSpan.frommilless(Configuration.HttpTimeout)
而不是new TimeSpan(Configuration.HttpTimeout)