我正在将使用基于回调的 WCF Web 服务的旧 Silverlight 应用程序转换为使用基于等待任务的 WCF Web 服务的 OpenSilver。我试图弄清楚如何处理错误情况。这是基于回调的代码:
private void GetNextImage()
{
var cmc = ServiceFactories.CreateCartManager();
cmc.getSlideImageCompleted += (s, e) =>
{
cmc_getSlideImageCompleted(s, e);
};
var lastTime = SystemSettings.GetInstance().SlideShowData.LastImageTime;
cmc.getSlideImageAsync(string.IsNullOrEmpty(lastTime) ? null : lastTime);
}
void cmc_getSlideImageCompleted(object sender, getSlideImageCompletedEventArgs e)
{
if (e.Cancelled)
{
GetNextImage();
}
else if (e.Error != null)
{
var errMsg = new ErrorWindow("Error while trying to get next image in slide show:", msg);
errMsg.Show();
}
else if (e.Result == null)
{
// There are no images in the slide show right now.
}
else
{
// we have an image!!!!
var imageData = e.Result.imageData;
// <the rest of the code>
}
}
我知道 GetNextImage() 应该是这样的:
private async Task GetNextImage()
{
var cmc = ServiceFactories.CreateCartManager();
var lastTime = SystemSettings.GetInstance().SlideShowData.LastImageTime;
var result = await cmc.getSlideImageAsync(string.IsNullOrEmpty(lastTime) ? null : lastTime);
cmc_getSlideImageCompleted(result);
}
void cmc_getSlideImageCompleted(getSlideImageResponse e)
{
...
}
问题是,e.Cancelled、e.Error 和 e.Result 发生了什么?我现在如何解释较低级别的错误?
回答1
e.Cancelled、e.Error 和 e.Result 发生了什么?
e.Cancelled
如果您有异步方法(在您的情况下为 cmc.getSlideImageAsync
),则可以通过 https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=net-6.0 取消它。在此方法中,如果您反复检查是否已请求取消(通过 ThrowIfCancellationRequested
),那么它将抛出一个 OperationCanceledException
(或派生类)。
所以, e.Cancelled
的等价物是这样的:
getSlideImageResponse response;
try
{
response = await cmc.getSlideImageAsync(..., cancellationToken);
}
catch(OperationCanceledException ex)
{
//if(e.Cancelled) logic goes here
}
e.Error
如果您的异步方法由于某种原因失败,那么它将填充底层 Task
的 https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.exception?view=net-6.0 属性。
Task<getSlideImageResponse> getTask = cmc.getSlideImageAsync(...);
getTask.Wait(); //BAD PRACTICE, JUST FOR DEMONSTRATION PURPOSES
if(getTask.Exception != null)
{
//if(e.Error != null) logic goes here
}
上面的代码不是最理想的,因为 .Wait
是一个阻塞调用,可能会导致死锁。推荐的方法是使用 await
。这个操作符可以从 Task
中检索 .Exception
属性并且可以再次抛出它:
getSlideImageResponse response;
try
{
response = await cmc.getSlideImageAsync(...);
}
catch(Exception ex)
{
//if(e.Error != null) logic goes here
}
e.Result
仅当方法未取消或未失败时才填充此属性。这里也是如此:
getSlideImageResponse response;
try
{
response = await cmc.getSlideImageAsync(..., cancellationToken);
}
catch(OperationCanceledException ocex)
{
//if(e.Cancelled) logic goes here
}
catch(Exception ex)
{
//if(e.Error != null) logic goes here
}
//if(e.Result != null) logic goes here