gpt4 book ai didi

c# - 为什么使用 WebClient 的 UploadFileAsync 没有错误通知?

转载 作者:行者123 更新时间:2023-11-30 14:46:14 28 4
gpt4 key购买 nike

当我执行以下代码时:

public static async Task UploadFile(string serverPath, string pathToFile, string authToken)
{
serverPath = @"C:\_Series\S1\The 100 S01E03.mp4";
var client = new WebClient();
var uri = new Uri($"http://localhost:50424/api/File/Upload?serverPath={WebUtility.UrlEncode(serverPath)}");
client.UploadProgressChanged += UploadProgressChanged;
client.UploadFileCompleted += UploadCompletedCallback;
//client.UploadFileAsync(uri, "POST", pathToFile);
client.UploadFile(uri, "POST", pathToFile);
}

我得到异常:

System.Net.WebException: 'The remote server returned an error: (404) Not Found.'

我不太担心 404,我正忙于追查为什么 WebClient 找不到它,但我最担心的是如果我调用 UploadFileAsync 具有相同的 uri,该方法就像没有任何错误一样执行。

出现问题的唯一迹象是两个事件处理程序均未被调用。我强烈怀疑我没有得到异常,因为异步调用不是 async/await 而是基于事件的,但是我期望某种事件或属性表明发生了异常。

如何在生产中使用隐藏此类错误的代码,尤其是相对常见的网络错误?

最佳答案

Why no error notification for UploadFileAsync with WebClient?

引用 WebClient.UploadFileAsync Method (Uri, String, String) Remarks

The file is sent asynchronously using thread resources that are automatically allocated from the thread pool. To receive notification when the file upload completes, add an event handler to the UploadFileCompleted event.

强调我的。

您不会收到任何错误,因为它正在另一个线程上执行,以免阻塞当前线程。要查看错误,您可以通过 UploadFileCompletedEventArgs.Exception 在声明的事件处理程序中访问它。 .

我很好奇为什么要使用 WebClient而不是 HttpClient这已经主要是异步的,但后来我的假设是因为上传进度。

我建议包装 WebClientTask 中调用事件处理程序使用 TaskCompletionSource利用自来水。

以下类似于此处提供的示例 How to: Wrap EAP Patterns in a Task

public static async Task UploadFileAsync(string serverPath, string pathToFile, string authToken, IProgress<int> progress = null) {
serverPath = @"C:\_Series\S1\The 100 S01E03.mp4";
using (var client = new WebClient()) {
// Wrap Event-Based Asynchronous Pattern (EAP) operations
// as one task by using a TaskCompletionSource<TResult>.
var task = client.createUploadFileTask(progress);

var uri = new Uri($"http://localhost:50424/api/File/Upload?serverPath={WebUtility.UrlEncode(serverPath)}");
client.UploadFileAsync(uri, "POST", pathToFile);
//wait here while the file uploads
await task;
}
}

在哪里createUploadFileTask是一种自定义扩展方法,用于包装 WebClient 的基于事件的异步模式 (EAP) 操作作为一项任务,使用 TaskCompletionSource<TResult> .

private static Task createTask(this WebClient client, IProgress<int> progress = null) {
var tcs = new TaskCompletionSource<object>();
#region callbacks
// Specifiy the callback for UploadProgressChanged event
// so it can be tracked and relayed through `IProgress<T>`
// if one is provided
UploadProgressChangedEventHandler uploadProgressChanged = null;
if (progress != null) {
uploadProgressChanged = (sender, args) => progress.Report(args.ProgressPercentage);
client.UploadProgressChanged += uploadProgressChanged;
}
// Specify the callback for the UploadFileCompleted
// event that will be raised by this WebClient instance.
UploadFileCompletedEventHandler uploadCompletedCallback = null;
uploadCompletedCallback = (sender, args) => {
// unsubscribing from events after asynchronous
// events have completed
client.UploadFileCompleted -= uploadCompletedCallback;
if (progress != null)
client.UploadProgressChanged -= uploadProgressChanged;

if (args.Cancelled) {
tcs.TrySetCanceled();
return;
} else if (args.Error != null) {
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
} else
//since no result object is actually expected
//just set it to null to allow task to complete
tcs.TrySetResult(null);
};
client.UploadFileCompleted += uploadCompletedCallback;
#endregion

// Return the underlying Task. The client code
// waits on the task to complete, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}

更进一步,创建另一种扩展方法来包装上传文件,使其可以等待...

public static Task PostFileAsync(this WebClient client, Uri address, string fileName, IProgress<int> progress = null) {
var task = client.createUploadFileTask(progress);
client.UploadFileAsync(address, "POST", fileName);//this method does not block the calling thread.
return task;
}

允许您的 UploadFile重构为

public static async Task UploadFileAsync(string serverPath, string pathToFile, string authToken, IProgress<int> progress = null) {
using (var client = new WebClient()) {
var uri = new Uri($"http://localhost:50424/api/File/Upload?serverPath={WebUtility.UrlEncode(serverPath)}");
await client.PostFileAsync(uri, pathToFile, progress);
}
}

这现在允许您异步调用上传,甚至可以使用您自己的 Progress Reporting (Optional) 跟踪进度

例如,如果在基于 XAML 的平台中

public class UploadProgressViewModel : INotifyPropertyChanged, IProgress<int> {

public int Percentage {
get {
//...return value
}
set {
//...set value and notify change
}
}

public void Report(int value) {
Percentage = value;
}
}

或使用开箱即用的 Progress<T> Class

所以现在您应该能够在不阻塞线程的情况下上传文件,并且仍然能够等待它、获取进度通知和处理异常,前提是您有一个 try/catch。

关于c# - 为什么使用 WebClient 的 UploadFileAsync 没有错误通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50198070/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com