I am converting over an old Silverlight application that used callback-based WCF Web Services over to OpenSilver that is using awaitable task based WCF Web Services. I am trying to figure out how to handle the error conditions. Here is the callback-based code:
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>
}
}
I know that GetNextImage() should look like this:
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)
{
...
}
The question is, what happened to e.Cancelled, e.Error, and e.Result? How do I account for that lower level errors now?
CodePudding user response:
What happened to e.Cancelled, e.Error, and e.Result?
e.Cancelled
If you have an async method (in your case the cmc.getSlideImageAsync
) then this can be cancelled through a CancellationToken
. Inside this method if you repeatedly check where the cancellation has been requested or not (via the ThrowIfCancellationRequested
) then it will throw a OperationCanceledException
(or a derived class).
So, the equivalent of e.Cancelled
is this:
getSlideImageResponse response;
try
{
response = await cmc.getSlideImageAsync(..., cancellationToken);
}
catch(OperationCanceledException ex)
{
//if(e.Cancelled) logic goes here
}
e.Error
If your async method fails for whatever reason then it will populate the underlying Task
's Exception
property.
Task<getSlideImageResponse> getTask = cmc.getSlideImageAsync(...);
getTask.Wait(); //BAD PRACTICE, JUST FOR DEMONSTRATION PURPOSES
if(getTask.Exception != null)
{
//if(e.Error != null) logic goes here
}
The above code is suboptimal since the .Wait
is a blocking call and can cause deadlock. The recommended approach is to use await
. This operator can retrieve the .Exception
property from the Task
and can throw it again:
getSlideImageResponse response;
try
{
response = await cmc.getSlideImageAsync(...);
}
catch(Exception ex)
{
//if(e.Error != null) logic goes here
}
e.Result
This property was populated only if the method was not cancelled or did not fail. The same is true here:
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