c# - 将 WCF Web 服务调用从基于回调的异步方法转换为等待任务

我正在将使用基于回调的 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

如果您的异步方法由于某种原因失败,那么它将填充底层 Taskhttps://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

相似文章