RX and Exception Handling - c#

I'm using the reactive extensions for a kind of a in process message bus.
The implementation is quite simple.
Register looks like
public IDisposable Register<T>(Action<T> action) where T : IMessage
{
return this.subject
.OfType<T>()
.Subscribe(action);
}
And send simply:
private void SendMessage(IMessage message)
{
this.subject.OnNext(message);
}
However i'm now having some trouble with the exception behaviour of RX.
One an exception is thrown in a registered/subscribed action - the Observable 'stream' is broken and will not subscribe anymore.
Sine this message bus is used for two parts of the application to communicate i need to ensure that such a stream is never broken even if an unexpected exception is thrown.

If you need to ensure that the stream is never broken by an exception, then you need to have another channel for the exceptions.
This behavior is not completely unexpected. From the documentation for the IObserver<T> interface:
The OnError method, which is typically called by the provider to indicate that data is unavailable, inaccessible, or corrupted, or that the provider has experienced some other error condition.
Given this, if the stream is unavailable, corrupted, etc, you definitely want the stream to be "faulted" (this is analagous to a channel being faulted in WCF); the state is indeterminate so you can't rely on anything else that comes from the IObservable<T> implementation; so why should there be an expectation that there will be any more observations?
That said, you have a some options:
Swallow the exception
You'd have to wrap the action delegate that you pass into your Register function, like so:
public IDisposable Register<T>(Action<T> action) where T : IMessage
{
return this.subject
.OfType<T>()
.Subscribe(t => {
// Execute action
try { action(t); }
catch { }
});
}
This, of course, might not be desirable, as you might be throwing away exceptions which impact your program (or, you might know exactly what's going on here, and want to skip them), but it can be used to build on the next solution.
Provide an action to take when an exception is thrown
Using the above as the base, you can ask for an Action<T, Exception> which will be called when an exception is thrown.
public IDisposable Register<T>(Action<T> action,
Action<T, Exception> errorHandler) where T : IMessage
{
return this.subject
.OfType<T>()
.Subscribe(t => {
// Execute action
try { action(t); }
catch (Exception e) { errorHandler(t, e); }
});
}
Now, when an exception is thrown from action, it will be passed to your exception handler without breaking the stream.
The above can easily be overloaded to provide the behavior which will swallow the exception (which again, may or may not serve your purposes):
public IDisposable Register<T>(Action<T> action) where T : IMessage
{
// Call the overload, don't do anything on
// exception.
return Register(action, (t, e) => { });
}

Basically you can provide an OnError delegate on the Subscribe method. I've written a small tutorial that takes this matter into consideration (Exception Handling), quite recently on my blog : http://blog.andrei.rinea.ro/2013/06/01/bing-it-on-reactive-extensions-story-code-and-slides/
Have look at the OnError method. Basically you need to resubscribe since the Rx framework is built on the premise that a sequence is broken when an error has occured.

Related

Silence specific Exception

I have a lot of throw new NotImplementedExceptions() throughout my whole application. For now I want to silence them and to show a custom Message Dialog instead.
For catching them I'm using:
AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
if(eventArgs.Exception is NotImplementedException) {
return;
}
}
But the problem is that the exception is still threw.
How can I silence the throw when I catch this type of Exception within this piece of code?
It sounds like what you want to do is to do something nicer than exploding when a method you haven't implemented is invoked. I don't believe that is possible using AppDomain.FirstChanceException or the related UnhandledException. There's a good answer here that talks a bit about why simply suppressing exceptions is undesirable.
What you could do instead is use something besides raising an exception to mark methods as not implemented, like calling a helper that displays your message, when you haven't implemented something yet. You could use #if pragmas or the ConditionalAttribute to switch to actually throwing exceptions in non-DEBUG builds, if that's desirable. It's not that uncommon to use helpers for throwing exceptions anyway (see for example ThrowHelper in the BCL, or Throw in one of my own projects), as there are some benefits to avoiding throws.
This would look like:
public void UnImplementedMethod()
{
// rather than "throw new NotImplementedException("some message")"
MyHelper.NotImplemented("some message");
}
// ....
static class MyHelper
{
[Conditional("DEBUG")]
public static void NotImplemented(string msg)
{
#if DEBUG // can use whatever configuration parameter
MessageBox.Show("Not Implemented: "+ msg);
#else
throw new NotImplementedException(msg);
#endif
}
}
You can use generic parameters to handle unimplemented methods that have non-void returns, though you have to decide what to actually return if you don't throw an exception. With this pattern you can do whatever you'd like, and still easily find places that haven't been implemented.

Returing to action method after global exception handler execution

I would like to globally catch any exception that is thrown in my models and controllers because I assume following logic in every action method:
public ActionResult SomeActionMethod(SomeViewModel someViewModel)
{
try
{
// Do operation that may throw exception
}
catch (BLLException e)
{
ModelState.AddModelError("Error", e.Message);
}
catch (Exception e)
{
_log.Info(e);
RedirectToAction("ErrorPage", "ErrorControler");
}
return View(someViewModel);
}
A business logic layer will throw exceptions that user will be able to handle, and a message about that exception will be displayed to him. All other kinds of exception will be saved on server log and user will get an error page.
So since that logic will repeat in every controller I decided to move it to a global exception handler. But the question is: is it possible to go back from exception handler attribute to a line in action where it was thrown? I would like to achieve something like:
public class ExceptionGlobalHandler : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if( filterContext.Exception.GetType() == typeof(BLLException))
{
ModelState.AddModelError("Error", e.Message);
//Continue executing where excetpion was thrown
}
catch (filterContext.Exception.GetType() == typeof(BLLException))
{
_log.Info(e);
RedirectToAction("ErrorPage", "ErrorControler");
}
}
}
Is it clear solution, and what is the best way of doing it?. What do you think about that kind of approach?
Unfortunately I don't think there is a way in C# to do this, however you could build in some logic to do it for you.
In your Action's code, you'd just have to throw the exception later on, like record the exception internally and throw it only at the end of the method. For example:
public void SomeAction()
{
Exception innerEx;
try
{
//some code that may/may not cause exceptions.
}catch(Exception e)
{
innerEx = e;
}
//some more execution code, equivelent to your "carry on at line x"
throw innerEx;
}
Obviously this means your action's code would have to change, in addition to the wrapper you're using, but this, I think, is the unfortunate problem you have :(
TBH, I think you should rewrite the action's code, because a program that crashes should stop executing, and developers will generally put error checking code within their methods.
( to avoid confusion, I've been using Action to mean the System.Action class, NOT the mvc action class, because I know quite little about MVC, though I hope it makes sense anyway :P )
I would also say there may be something you've been missing - Have you considered seperating the methods you're calling into multiple separate calls? Thus, you could call them all at once, reacting appropriately on an Exception result from one of the calls, while the others will carry on happily.

Invoke a method through reflection without getting TargetInvocationException

I've found a method using reflection (and got it's MethodInfo). How can I invoke it without getting TargetInvocationException when exceptions are thrown?
Update
I'm creating a command implementation where the commands are handled by classes which implemement
public interface ICommandHandler<T> where T : class, ICommand
{
public void Invoke(T command);
}
Since there is one dispatcher which takes care of find and map all handlers to the correct command I can't invoke the methods directly but by using reflection. Something like:
var handlerType = tyepof(IHandlerOf<>).MakeGenericType(command.GetType());
var method = handlerType.GetMethod("Invoke", new [] { command.GetType() });
method.Invoke(theHandler, new object[]{command});
It works fine, but I want all exceptions to get passed on to the code that invoked the command.
So that the caller can use:
try
{
_dispatcher.Invoke(new CreateUser("Jonas", "Gauffin"));
}
catch (SomeSpecificException err)
{
//handle it.
}
Instead of having to catch TargetInvocationException.
(I know that I can throw the inner exception, but that's pretty worthless since the stack trace is destroyed)
Update2
Here is a possible solution..
But it seems more like a hack. Aren't there a better solution? Maybe with expressions or something?
Create a Delegate from the MethodInfo (through one of the overloads of Delegate.CreateDelegate) and invoke that instead. This won't wrap any exception thrown by the method inside a TargetInvocationException like MethodInfo.Invoke does.
class Foo
{
static void ThrowingMethod()
{
throw new NotImplementedException();
}
static MethodInfo GetMethodInfo()
{
return typeof(Foo)
.GetMethod("ThrowingMethod", BindingFlags.NonPublic | BindingFlags.Static);
}
// Will throw a NotImplementedException
static void DelegateWay()
{
Action action = (Action)Delegate.CreateDelegate
(typeof(Action), GetMethodInfo());
action();
}
// Will throw a TargetInvocationException
// wrapping a NotImplementedException
static void MethodInfoWay()
{
GetMethodInfo().Invoke(null, null);
}
}
EDIT:
(As the OP has pointed out, DynamicInvoke won't work here since it wraps too)
Based on your update, I would just use dynamic:
((dynamic)theHandler).Invoke(command);
You can't. That's the specified way that exceptions are propagated by invoking a method via reflection. You can always catch TargetInvocationException and then throw the "inner" exception obtained via the InnerException property, if you want the effect to be the original exception being thrown.
(You'll lose the original stack trace, mind you. It's possible that there's a way to prevent that, but it's tricky. I believe there may be more support for this in .NET 4.5; I'm not sure.)
You can call Invoke on the mehtodinfo instance, but the first argument of the call is the target (The object that the method info belongs to). If you pass this and it has access to call it, you should not get the exception.

How can an exception bubble up beyond this task?

I thought this approach would be safe, in that it wouldn't allow exceptions to propagate. A colleague of mine suggested that the exceptions may need to be observed on the main thread, and should thus be passed up to the main thread. Is that the answer? Can you see how an exception could leak through this?
private static void InvokeProcessHandlers<T>(List<T> processHandlers, Action<T> action)
{
// Loop through process handlers asynchronously, giving them each their own chance to do their thing.
Task.Factory.StartNew(() =>
{
foreach (T handler in processHandlers)
{
try
{
action.Invoke(handler);
}
catch (Exception ex)
{
try
{
EventLog.WriteEntry(ResourceCommon.LogSource,
String.Format(CultureInfo.CurrentCulture, "An error occurred in a pre- or post-process interception handler: {0}", ex.ToString()),
EventLogEntryType.Error);
}
catch (Exception)
{
// Eat it. Nothing else we can do. Something is seriously broken.
}
continue; // Don't let one handler failure stop the rest from processing.
}
}
});
}
By the way, a stack trace is indeed showing that an exception is leaking from this method.
The exception is AccessViolation, and I believe it has to do with the code that calls this method:
InvokeProcessHandlers<IInterceptionPostProcessHandler>(InterceptionPostProcessHandlers, handler => handler.Process(methodCallMessage, methodReturnMessage));
The getter for InterceptionPostProcessHandlers contains this:
_interceptionPreprocessHandlers = ReflectionUtility.GetObjectsForAnInterface<IInterceptionPreprocessHandler>(Assembly.GetExecutingAssembly());
Just make sure to check parameter for null references before you iterate
other than that there is nothing wrong as log writing is not something to stop the execution, but i would recommend to make it more clean and maintainable by encapsulating the logging into a mothod like:
bool Logger.TryLog(params);
and inside this method do the try with a catch that returns false and if you want to handle it in client code do it and if you dont never mind just call the logger in a clean encapsulated way
A colleague of mine suggested that the exceptions may need to be
observed on the main thread, and should thus be passed up to the main
thread.
How can it be "passed up to the main thread"? The main thread is away and doing its own thing.
The best you can do is to make it configurable and accept an ExceptionHandler delegate that is called.

Handling a class that doesn't throw exception in c#

I've got some UI code that looks like this:
try
{
SomeClass classInstance = new SomeClass(someId);
}
catch (Exception exception)
{
// Content wasn't created, show a message, stop processing
return;
}
It seems the try catch was added because the constructor for SomeClass would bomb out if the someId it receives isn't valid, and data couldn't be found in a DB.
Running this code through FXCop recently, it warns against using the general Exception, but all SomeClass does is throw a new Exception with a message to say it failed to initialize.
I guess the problem is that the class constructor should have it's own custom exception, which I could then handle in my UI, but I wonder what else I could do to the code above to handle the exception, that meets FXCop requirements?
FxCop's rule exists because the catch (Exception) block above catches all possible exceptions, including low-level exceptions like StackOverflowException that you probably can't catch in a useful way.
The right approach is definitely to throw a more specific type: either one you've invented, or an existing .NET framework exception type that closely matches your situation. (When in doubt, I normally go for InvalidOperationException.)
Alternatively, you could check the exact exception type when catching it. This won't prevent the FxCop warning, but it should address the underlying problem:
catch (Exception exception)
{
if (exception.GetType() == typeof(Exception))
{
// Content wasn't created, show a message, stop processing
return;
}
else
{
// Some other exception type that wasn't thrown from our code -
// delegate to a higher-level exception handler
throw;
}
}
You don't need a custom exception; just use one of the dozens that already exist in the framework for given circumstances. If someId is bad, throw an ArgumentException -- that's what it's made for. If something's null that shouldn't be, a NullReferenceException will occur; just let it be thrown. Etc. Throwing a plain Exception is a bit like saying "something went wrong -- read the message for details" rather than "this went wrong".
FxCop is complaining about catch (Exception) because it's too commonly abused to swallow up all exceptions rather than letting them propagate and be handled by code that knows how to do so. You should be able to say what types of exceptions are being thrown and catch those, while letting those you don't recognize make their way up the call stack.
You should fix the class constructor. Throwing Exception is never a good idea.
However, to work around the issue you have temporarily (as this is a horrible, unreliable hack), you could check the message of the exception against the one you're expecting:
catch (Exception exception)
{
if (exception.Message == "whatever your class sets the message to")
// Content wasn't created, show a message, stop processing
return;
else
// Any other exception should bubble
throw;
}
Using InvalidOperationException in place of throwing Exception sounds like it might be sensible.
If FXCop doesn't like handling the general Exception (and I tend to agree) then maybe you have access to SomeClass's source code. Modify the constructor to throw an exception that is more specific, e.g. ArgumentOutOfRangeException or some custom exception.
In that case your code would then look as follows:
try
{
SomeClass classInstance = new SomeClass(someId);
}
catch(ArgumentOutOfRangeException exception)
{
// Content wasn't created, show a message, stop processing
return;
}
As many others have said, the constructor should not be throwing a naked Exception. Seeing that the constructor retrieves data from DB and throws based on the result, the best solution is to create your own exception class.
Creating exceptions is super-easy in Visual studio. Just type in Exception and press TAB. It will then create the exception class with required constructors(all four of them). Do not be afraid to create classes that don't do very much, that's what they are designed for.
This is how I would write this class:
public class SomeClass {
public SomeClass(int someId) {
if (someId < 0) //validation on the ID, can it be negative?
throw new ArgumentException("someId", "ID cannot be negative");
//Perform DB operation
if (/*DB error - not found*/)
throw new DataNotFoundException("Cannot find record with ID " + someId);
}
}
[Serializable]
public class DataNotFoundException : Exception {
public DataNotFoundException() { }
public DataNotFoundException(string message) : base(message) { }
public DataNotFoundException(string message, Exception inner) : base(message, inner) { }
protected DataNotFoundException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}

Categories