[英]Handle "A task was canceled" exception
My C# app uploads file to some API, I'm using multipart request, ie I'm uploading a json string and binary contect of the file, it works fine for most files, but for very few it gives exception, I mean let's try for file named 50MB.zip
I'm getting the exception:我的 C# 应用程序将文件上传到某个 API,我使用的是多部分请求,即我正在上传文件的 json 字符串和二进制内容,它适用于大多数文件,但对于极少数文件,它给出了例外,我的意思是让我们尝试对于名为
50MB.zip
文件,我收到异常:
A task was canceled. ::: ::: System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
My code looks roughly as follows:我的代码大致如下:
public async Task<Dictionary<string , string>> Upload(string filePath)
{
FileInfo fi = new FileInfo(FilePath);
string jsonString="some json string";
byte[] fileContents=File.ReadAllBytes(fi.FullName);
Uri webService = new Uri(url);
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post , webService);
requestMessage.Method = HttpMethod.Post;
requestMessage.Headers.Add("Authorization" , "MyKey1234");
const string boundry = "------------------My-Boundary";
MultipartFormDataContent multiPartContent = new MultipartFormDataContent(boundry);
ByteArrayContent byteArrayContent = new ByteArrayContent(fileContents);
multiPartContent.Add(byteArrayContent);
requestMessage.Content = multiPartContent;
HttpClient httpClient = new HttpClient();
HttpResponseMessage httpResponse = await httpClient.SendAsync(requestMessage , HttpCompletionOption.ResponseContentRead , CancellationToken.None);
//exception in this line ^
return new Dictionary<string , string>();
}
The caller:呼叫者,召集者:
myDictionary = await Upload(filePath);
The structure of the console app is as follows:控制台应用程序的结构如下:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
new MyClass().Start();
}
}
And inside MyClass:
在
MyClass:
public async void Start()
{
myDictionary = await Upload(filePath);
}
I guess I'm not using async correctly, can you maybe see what I'm missing?我想我没有正确使用异步,你能看到我错过了什么吗? any ideas?
有任何想法吗?
I'm 99% sure this error is due to a timeout, or the fact you don't actually await your Start
method in MainAsync
我 99% 肯定这个错误是由于超时,或者你实际上没有在
MainAsync
等待你的Start
方法
I've addressed the timeout issue in the follow code along with some other small changes, which don't necessarily answer your question but hopefully help you nevertheless我已经解决了以下代码中的超时问题以及其他一些小的更改,这些更改不一定能回答您的问题,但希望对您有所帮助
class Program
{
private static HttpClient httpClient;
static void Main(string[] args)
{
httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("your base url");
// add any default headers here also
httpClient.Timeout = new TimeSpan(0, 2, 0); // 2 minute timeout
MainAsync().Wait();
}
static async Task MainAsync()
{
await new MyClass(httpClient).StartAsync();
}
}
What I've done here is move the HttpClient
out from your Upload()
method because this class is designed to be reused many times.我在这里所做的是将
HttpClient
从您的Upload()
方法中移出,因为此类旨在多次重用。 I've passed the httpClient
object to MyClass
's constructor which you'll see in the next code snippet.我已将
httpClient
对象传递给MyClass
的构造函数,您将在下一个代码片段中看到它。
I've also changed MainAsync()
to await
the StartAsync
(renamed from Start to StartAsync because it's convention to suffix async methods) because in your original code MainAsync()
wasn't actually awaiting anything我也改变了
MainAsync()
以await
该StartAsync
(更名从开始到StartAsync,因为它的约定,以后缀异步方法),因为你原来的代码MainAsync()
实际上并没有任何等待
As I mentioned in the comments, you can change MainAsync().Wait()
to await MainAsync()
if you change Main
to be static async Task Main
, which will require you to change your build language to C# 7.1 or above正如我在评论中提到的,如果您将
Main
更改为static async Task Main
,您可以将MainAsync().Wait()
更改为await MainAsync()
,这将要求您将构建语言更改为 C# 7.1 或更高版本
public class MyClass
{
private Dictionary<string, string> myDictionary;
private readonly HttpClient httpClient;
public MyClass(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task StartAsync()
{
myDictionary = await UploadAsync("some file path");
}
public async Task<Dictionary<string, string>> UploadAsync(string filePath)
{
byte[] fileContents;
using (FileStream stream = File.Open(filePath, FileMode.Open))
{
fileContents = new byte[stream.Length];
await stream.ReadAsync(fileContents, 0, (int)stream.Length);
}
HttpRequestMessage requestMessage = new HttpRequestMessage();
// your request stuff here
HttpResponseMessage httpResponse = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
// parse response and return the dictionary
}
}
In MyClass
I've made the following changes在
MyClass
我进行了以下更改
Added a HttpClient
parameter to the class' constructor, so we can pass our global HttpClient object to this class for it to reuse (which is what we do in MainAsync()
)向类的构造函数添加了
HttpClient
参数,因此我们可以将全局 HttpClient 对象传递给此类以供其重用(这就是我们在MainAsync()
中MainAsync()
)
As mentioned before, I've renamed Start
and Upload
to StartAsync
and UploadAsync
because it's good practice to suffix async methods with Async正如前面提到的,我已经更名为
Start
并Upload
到StartAsync
和UploadAsync
,因为它是很好的做法,后缀异步与异步方法
Start
was changed from void
to a Task
because you should only use async void
for event handlers Start
已从void
更改为Task
因为您应该仅将async void
用于事件处理程序
I changed the way your file is read to also be async, because it seems wasteful to have an async
method that then blocks the CPU waiting for File.ReadAllBytes
to finish.我将读取文件的方式更改为异步,因为使用
async
方法然后阻塞 CPU 等待File.ReadAllBytes
完成似乎很浪费。 Wherever possible you should use async/await for I/O.在可能的情况下,您应该对 I/O 使用 async/await。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.