我的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();
}
}
我在这里所做的是将
HttpClient
从Upload()
方法中移出,因为此类被设计为可以重复使用多次。我已经将httpClient
对象传递给MyClass
的构造函数,您将在下一个代码片段中看到该构造函数。我还更改了
MainAsync()
到await
的StartAsync
(从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()
中所做的事情)如前所述,我已将
Start
和Upload
重命名为StartAsync
和UploadAsync
,因为将异步方法后缀为Async是一种好习惯Start
从void
更改为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/