简体   繁体   English

处理“任务被取消”异常

[英]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()awaitStartAsync (更名从开始到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 changesMyClass我进行了以下更改

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正如前面提到的,我已经更名为StartUploadStartAsyncUploadAsync ,因为它是很好的做法,后缀异步与异步方法

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM