我的C#应用​​程序将文件上传到某些API,我使用的是多部分请求,即我正在上传文件的json字符串和二进制连接,它对大多数文件都适用,但是对于极少数的文件,它会给出异常,我的意思是让我们尝试用于名为50MB.zip的文件
我得到了异常(exception):

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()
我的代码大致如下:
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>();
}
调用者,召集者:
myDictionary = await Upload(filePath);
控制台应用程序的结构如下:
class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }

    static async Task MainAsync()
    {
        new MyClass().Start();
    }
}
并在MyClass:
public async void Start()
{
    myDictionary = await Upload(filePath);
}
我想我没有正确使用异步,您也许能看到我所缺少的内容吗?有任何想法吗?

最佳答案

我99%确信此错误是由于超时引起的,或者您实际上没有等待Start中的MainAsync方法的事实

我已经解决了以下代码中的超时问题以及其他一些小的更改,这些更改不一定能回答您的问题,但希望能对您有所帮助

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();
    }
}

我在这里所做的是将HttpClientUpload()方法中移出,因为此类被设计为可以重复使用多次。我已经将httpClient对象传递给MyClass的构造函数,您将在下一个代码片段中看到该构造函数。

我还更改了MainAsync()awaitStartAsync(从Start改为StartAsync,因为习惯上将后缀异步方法重命名),因为在您的原始代码中MainAsync()实际上并没有等待任何东西

正如我在评论中提到的,如果您将MainAsync().Wait()更改为await MainAsync(),则可以将Main更改为static async Task Main,这将需要您将构建语言更改为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
    }
}

MyClass中,我进行了以下更改

在类的构造函数中添加了HttpClient参数,因此我们可以将全局HttpClient对象传递给此类以供重用(这是我们在MainAsync()中所做的事情)

如前所述,我已将StartUpload重命名为StartAsyncUploadAsync,因为将异步方法后缀为Async是一种好习惯
Startvoid更改为Task because you should only use async void for event handlers

我将读取文件的方式也更改为异步,因为拥有async方法似乎很浪费,该方法随后阻塞了CPU等待File.ReadAllBytes完成。只要有可能,就应该对I/O使用async/await。

关于c# - 处理 "A task was canceled"异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51594036/

10-09 17:53