我的C#应用程序将文件上传到某个API,我正在使用多部分请求,即,我正在上传文件的json字符串和二进制连接,它适用于大多数文件,但很少有异常,我意味着我们尝试使用名为50MB.zip
的文件
我遇到了例外情况:
任务被取消。 ::::: System.Threading.Tasks.TaskCanceledException:任务被取消。 在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在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);
}
我想我没有正确使用异步,也许您能看到我所缺少的吗?有什么想法吗?
答案 0 :(得分:2)
我有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()
的{{1}}更改为await
(由于从后缀的异步方式开始习惯将它从Start改名为StartAsync),因为在您的原始代码StartAsync
中实际上没有等待任何事情
正如我在评论中提到的,如果将MainAsync()
更改为MainAsync().Wait()
,则可以将await MainAsync()
更改为Main
,这将需要您将构建语言更改为C#7.1或更高版本
static async Task Main
在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
,因为将异步方法后缀为Async是一个好习惯
UploadAsync
从Start
更改为void
because you should only use async void
for event handlers
我将文件的读取方式也更改为异步,因为拥有Task
方法似乎很浪费,该方法随后阻塞了CPU等待async
完成。尽可能将async / await用于I / O。