Error handling using delegates - c#

I have a common method that I'm using to handle a specific error that may come back from a number of functions:
protected async Task<T> RunMyMethod<T>(Func<T> method)
{
try
{
var returnValue = await Task.Run<T>(method);
return returnValue;
}
catch (MyCustomException)
{
// Force a clean shutdown of the software
ShutdownApplication();
return default(T);
}
}
Here's an example of how that is then used in a derived class:
private async Task<IEnumerable<MyData>> GetMyData()
{
var returnValue = await base.RunMyMethod<IEnumerable<MyData>>(() =>
{
var returnval = GetMyDataFromServer();
return returnval;
});
return returnValue;
}
When an exception of type MyCustomException occurs in GetMyDataFromServer() the software doesn't drop into the catch block. I get the following error in the function GetMyData():
An exception of type 'System.ServiceModel.FaultException`1' occurred in mscorlib.dll but was not handled in user code
Additional information: Exception of type 'MyCustomException' was thrown.
This is with only User-unhandled exceptions turned on.
GetMyDataFromServer() communicates with a WCF service. This service is what throws the error.
ChannelFactory<TChannel> cf = new ChannelFactory<TChannel>(endPointName);
Binding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
var clientCredentials = new ClientCredentials();
. . .
channel = cf.CreateChannel();
var data = channel.CallWCFService();
Having looked around on-line, it appeared that the correct way to handle this was to change the base method as follows:
protected async Task<T> RunMyMethod<T>(Func<T> method)
{
var returnValue = await Task.Run<T>(method).ContinueWith(e =>
{
ShutdownApplication();
return default(T);
}, TaskContinuationOptions.OnlyOnFaulted);
return returnValue;
}
When I run this, I'm obviously not trapping for the correct error message, but I'm just getting a TaskCancellationException.
So, I have two questions: is my conclusion about how to handle this exception correct and, if so, how do I trap a specific error; and why am I getting a TaskCancellationException?

You get TaskCancellationException because the continuation is cancelled as it's conditional (i.e. TaskContinuationOptions.OnlyOnFaulted) and the condition isn't met since the antecedent task wasn't faulted.
There's no reason to use that method of adding a continuation. Using async-await like you did at the start is good enough (and even simpler).
The issue is that you are trying to catch MyCustomException but that isn't the exception being thrown. Since you're using WCF the exception is FaultException. You can check the "real" exception stored in FaultException.InnerException.

Related

RX - rethrow an error in containing method

I need to translate an error in an RX stream (IObservable) into an exception in the method that contains the subscription to the stream
(because of this issue https://github.com/aspnet/SignalR/pull/1331 , Whereby errors arent serialised to clients.) Once this issue is fixed I will revert to handling error properly
e.g.
I have the following method
public IObservable<StreamItem> LiveStream()
{
_mySvc.Start();
return _mySvc.ThingChanged();
}
So I have tried to subscribe to the stream and rethrow the error, but it still doesnt get transmitted to the client:
public IObservable<StreamItem> LiveStream()
{
_mySvc.Start();
_mySvc.ThingChanged().Subscribe(item => {}, OnError, () => {});
return _mySvc.ThingChanged();
}
private void OnError(Exception exception)
{
throw new Exception(exception.Message);
}
What I need is the equivelent of throwing in the LiveStream method
e.g. this error is propogated to the client
public IObservable<StreamItem> LiveStream()
{
_mySvc.Start();
throw new Exception("some error message");
return _mySvc.ThingChanged();
}
any ideas how to achieve this?
I have found this as well, especially with a "contained" reactive pipeline—that is, one with a well-defined beginning and end. In situations like those, it may suffice to simply allow underlying exceptions to bubble up to the containing scope. But as you have found, that concept is rather foreign to Rx generally: what happens in the pipeline stays in the pipeline.
The only way out of this that I have found in a contained scenario is to "slip" the error out of the stream using Catch(), and hand back an empty IObservable to allow the stream to halt naturally (otherwise, you'll hang if you're awaiting an IObservable for completion).
This will not work within your LiveStream() method, because that context/scope should have passed out of existence long before you're consuming your stream. So, this will have to happen in the context that contains the whole pipeline.
Exception error = null;
var source = LiveStream()
.Catch<WhatYoureStreaming, Exception>(ex => {error = ex; return Observable.Empty<WhatYoureStreaming>(); })
...
await source; // if this is how you're awaiting completion
// not a real exception type, use your own
if (error != null) throw new ContainingException("oops", error);
Just don't throw error there at the end, you'll lose the original stack trace.
Try this code:
public IObservable<StreamItem> LiveStream()
{
_mySvc.Start();
return
_mySvc
.ThingChanged()
.Materialize()
.Do(x =>
{
if (x.Kind == NotificationKind.OnError)
{
OnError(x.Exception);
}
})
.Dematerialize();
}
I'm not sure that this is the best way to go - throwing exceptions like this can cause you grief inside a stream where you end up with the wrong exception handlers firing. You might need to find another solution.

NSubstitute, try catch is not working on async method configured to throw an exception

I'm using NSubstitute for mocking and faking. I'm working with EF6 and would like to setup the SaveChangesAsync-Method of the database context to throw an exception:
context.SaveChangesAsync().Throws(new DbUpdateException("", SqlExceptionHelper.CreateSqlException(2627)));
SaveChangesAsync is called within a method of my data repository like this:
try
{
var fromDatabase = await context.Entries.OfType<Document>().FirstOrDefaultAsync(d => d.Id == doc.Id);
if (fromDatabase == null)
{
fromDatabase = new Document();
context.Entries.Add(fromDatabase);
}
PatchEntity(fromDatabase, doc);
await context.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
var innerException = ex.InnerException as SqlException;
if (innerException != null && innerException.Number == 2627)
{
errors.Add(new DbValidationError(nameof(doc.Name), "A entry with the same Name already exists under the selected parent."));
}
}
And this is the line within my unit test:
var result = await repository.TryAddOrUpdateDocument(doc);
Unfortunately my test keeps failing with the reason, that my test method(!) is throwing the exception, I'm trying to catch. Adding a general exception catch block isn't working either, the exception is not being catched at all. The exception is bubbling up.
My test is declared as "public async Task...", but turning it into simply void and calling .Result on the async method of my repository doesn't help either. What is going on?
I think the problem is that the exception is thrown from the original call instead of from inside the returned Task as described here.
Try something like:
Func<int> throwDbEx = () => {
throw new DbUpdateException("", SqlExceptionHelper.CreateSqlException(2627));
};
context.SaveChangesAsync().Returns(Task.Run(throwDbEx));
I cannot be 100% sure, but you are probably facing the problem that exceptions thrown by async with void return type cannot be caught naturally. Read the section "Avoid Async Void" here:
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Even if it won't answer your problem, it is worth reading anyway...

Exception Thrown from Thread Pool Thread shown as Unhandled

I am firing off a Task of on a background thread pool thread via the following method
private async Task LoadCoreMatchDataAsync()
{
string errorMessage = String.Empty;
...
try
{
if (!HasConnection)
return;
IProgress<string> progressIndicator = new Progress<string>(LoadProgress);
EventsCollection = new BindableCollection<Taurus.MatchDetails>(
await MatchDataService.GetCollectionAsync(
this.client, progressIndicator, this.token));
...
}
catch (TimeoutException toe)
{
errorMessage = String.Format(
"Retrieval of the MatchDetails using connection " +
"\"{0}\" failed with the following TimeoutException: \"{1}\".",
this.ConnectionString,
toe.Message);
}
catch (OperationCanceledException)
{
// Do nothing, cancel silently.
}
// Display any errors.
if (!String.IsNullOrEmpty(errorMessage))
{
await dialogManager.ShowDialog<MessageDialogResult>(
new MessageBoxViewModel("Connection Timeout", errorMessage, mbs));
HasConnection = false;
}
}
where the GetCollectionAsync(...) method is
public async Task<BindableCollection<Taurus.MatchDetails>> GetCollectionAsync(
MongoClient client, IProgress<string> progressIndicator, CancellationToken token)
{
return await Task.Factory.StartNew<BindableCollection<Taurus.MatchDetails>>(() =>
{
... // Somewhere in here we get a TimeoutException thrown.
}, token);
}
the problem is that when in my call to await MatchDataService.GetCollectionAsync(...) I get an expected TimeoutException, VS2012 throws "a TimeoutException was unhandled by user code" message, when clearly I am handling the exception in the "continuation" in the correct way. If I continue rather than break, the exception is indeed caught and I get my expected error message. I am just not sure why VS2012 is telling me that the exception is unahandled?
I am essentially doing what is described clearly in on of Jon Skeets answers here https://stackoverflow.com/a/19865613/626442.
Thanks for your time.
You have "Just My Code" turned on (which I mentioned in my answer in the other question you reference). The debugger is indicating that "User code" (Your code) did not handle the exception--which is true. The exception is caught by the framework code and placed into a Task.
Turn off the "Just My Code" debugger setting (in my opinion, it is a feature that only causes confusion and has very limited usefulness).

Async/await exception and Visual Studio 2013 debug output behavior

I'm developing an application in C# that communicates with Dynamics NAV through web services. To reduce duplicate code and because there will be many endpoints, I have created a generic async/await method that executes the service calls and handle exceptions.
The method works but I'm seeing an unexpected behavior in the Visual Studio 2013 output window when an exception occur(and is handled).
Test code and output can be seen below.
My concern is the "A first chance exception of type..." lines which I'm seeing 4 times when using the async/await methods. Does this exception really occur 4 times?
When calling the service synchronously there's only one exception line which is expected.
Is this just Visual Studio 2013 or is there something wrong with my async/await code?
Is there maybe a better way of doing what I'm trying to accomplish?
class Program
{
static void Main(string[] args)
{
Debug.WriteLine("Synchronous...");
try
{
TestFunctions_PortClient service = new TestFunctions_PortClient();
service.Open();
string result = service.ErrorTest();
Debug.WriteLine(result);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine(string.Empty);
Debug.WriteLine("Async...");
NavServiceTest navService = new NavServiceTest();
navService.TestAsync();
Console.ReadLine();
}
}
class NavServiceTest
{
public async void TestAsync()
{
try
{
string result = await CallServiceAsync();
Debug.WriteLine(result);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private async Task<string> CallServiceAsync()
{
TestFunctions_PortClient service = new TestFunctions_PortClient();
service.Open();
ErrorTest_Result result = await ExecuteServiceAsync<ErrorTest_Result>(
service.InnerChannel,
service.Endpoint,
service.ErrorTestAsync());
return result.return_value;
}
private async Task<T> ExecuteServiceAsync<T>(IClientChannel channel, ServiceEndpoint endpoint, Task<T> source)
{
var tcs = new TaskCompletionSource<T>();
Task<T> task = tcs.Task;
try
{
Debug.WriteLine("ExecuteServiceAsync");
tcs.TrySetResult(await source);
}
catch (EndpointNotFoundException ex)
{
Debug.WriteLine("EndpointNotFoundException");
tcs.TrySetException(ex);
}
catch (FaultException ex)
{
Debug.WriteLine("FaultException");
tcs.TrySetException(ex);
}
catch (Exception ex)
{
Debug.WriteLine("Exception");
tcs.TrySetException(ex);
}
finally
{
if (channel != null)
{
if (channel.State == CommunicationState.Faulted)
channel.Abort();
else
channel.Close();
}
}
if (task.IsFaulted)
{
throw task.Exception.InnerException;
}
return task.Result;
}
}
Here's the output of the code above.
Synchronous...
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV
Async...
ExecuteServiceAsync
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
FaultException
A first chance exception of type 'System.ServiceModel.FaultException' occurred in ServiceTest.exe
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV
When an exception occurs in an async method, it doesn't just propagate up the stack like it does in synchronous code. Heck, the logical stack is likely not to be there any more.
Instead, the exception is stored in the task which represents the asynchronous operation. Then, when you await the asynchronous operation, the GetResult method of the TaskAwaiter will rethrow the original exception. If that isn't caught in your code, then it will be caught by the compiler-generated code again and put into the task that represents that operation, etc. So if you have a chain of asynchronous methods (as is often the case) and the deepest one throws an exception, the exception propagation will actually be a "throw in GetResult, catch, stuff into task" per link in the chain.
So yes, the exception is being thrown four times, in order to effectively only be thrown once. If you're worried about the efficiency of that, I suspect it's not too bad - because the logical stack trace is only determined once. I dare say it's less efficient than the synchronous version, but my general philosophy is that if you're seeing so many exceptions that they're affecting your performance significantly, then either you're overusing exceptions or your system is in a really bad state anyway, and performance is the least of your worries.

Unable to catch Webservice call method within try catch block

I am developing a WP8 application. I created a web service on out-systems and then I am calling those web service methods in my app:
ServiceReference1.WebServiceClient ws = new WebServiceClient();
try
{
ws.FetchInboxAsync(EmailId);
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
Now if the server is down, I expect the control to go into the catch block but it does not and I get the following exception:
An exception of type 'System.ServiceModel.CommunicationException'
occurred in System.ServiceModel.ni.dll but was not handled in user
code.
I do realize that the web service call method is asynchronous, so its exception would not be caught in try catch. On forums, people suggest using await keyword. But when I write
await ws.FetchInboxAsync(EmailId);
I get an error : Cannot await void.
I tried something mentioned in answers here, but still I get the same exception
You can subscribe to FetchInboxCompleted event:
ServiceReference1.WebServiceClient ws = new WebServiceClient();
ws.FetchInboxCompleted += new EventHandler<ServiceReference1.FetchInboxCompletedEventArgs>(c_FetchInboxCompleted);
ws.FetchInboxAsync(EmailId);
And in event handler, check the result:
static void c_FetchInboxCompleted(object sender, serviceReference1.FetchInboxCompletedEventArgs e)
{
// check e.Error which contains the exception, if any
}
If the auto-generated WCF client proxy supports it, you should be able to await a method ending with TaskAsync:
await ws.FetchInboxTaskAsync(EmailId);
If the auto-generated WCF client proxy doesn't define this method, then you can define it yourself as described on MSDN:
public static Task FetchInboxTaskAsync(this ServiceReference1.WebServiceClient client, string emailId)
{
return Task.Factory.FromAsync(client.BeginFetchInbox, client.EndFetchInbox, emailId, null);
}

Categories

Resources