Avoid Try Catch Stements with custom ErrorHandler class - C# - c#

I have a class which exposes some functionality,
and I want to ensure exceptions will be handled by a custom ErrorHandler class.
Currently I can achieve this by a try / catch statement per each method, and process the exception by the error handler there.
My question is if there is a better way / design pattern to do it.
Code:
public class BasicErrorHandler
{
public void ProcessException(Exception ex)
{
//Does error handling stuff
}
}
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
try
{
//Does Something
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
public void MethodB()
{
try
{
//Does Something Else
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
}

In keeping with DRY principles, you could just wrap your try...catch logic into into own method which takes a predicate of the actual work to do:
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
DoWork( () => {
// do something interesting here
});
}
public void MethodB()
{
DoWork( () => {
// do something else interesting here
});
}
private void DoWork(Action action)
{
try
{
action();
}
catch(Exception ex)
{
_errorHandler.ProcessException(ex);
}
}
}

I've crafted this quickly and without thinking too much in the implications, but if you want to avoid all the try/catch blocks, you could do something like:
public class BasicErrorHandler
{
public void ProcessException(Exception ex)
{
//Does error handling stuff
}
public void Do(Action act)
{
try
{
act();
}
catch(Exception ex)
{
ProcessException(ex);
}
}
}
And then use it like:
public class Manager
{
BasicErrorHandler _errorHandler;
public Manager()
{
_errorHandler = new BasicErrorHandler();
}
public void MethodA()
{
_errorHandler.Do(() => {
//Does Something
});
}
public void MethodB()
{
_errorHandler.Do(() => {
//Does Something Else
});
}
}

Design patterns are there to solve a problem. Which problem are you trying to solve? What is wrong with the Try Catch blocks?
Only thing I can imagine is you want to have more clean code. Some answers suggest a helper method with an action. Given the helper methods that encapsulate a delegate: Do consider the impact on your stack trace and debugging sessions using these delegates. It might make logging etc more hard to understand.
If your intend is to do separation of concern, I would say If you can't handle it, just don't catch the exception. Let the class invoking the method handle it. If you insist to have a handler in your class, I would suggest Inversion of Control. That way, your class is not in control of determining which class should handle its exceptions.

Rx .net is for You. Advanced error handling gives You the ability to highly customize Your error handling. Check out the pages about that.
For example:
var source = new Subject<int>();
var result = source.Catch<int, TimeoutException>(tx=>Observable.Return(-1));
result.Dump("Catch");
source.OnNext(1);
source.OnNext(2);
source.OnError(new ArgumentException("Fail!"));
You'll get the following output:
Catch-->1
Catch-->2
Catch failed-->Fail!
The number of retries, the handling of how much time a method can take, everything can be configured.

The following is an Aspect oriented method of soling the problem, this makes use of PostSharp to do the weaving.
[Serializable]
public class HandleExceptionsAttribute : OnExceptionAspect {
/// <summary>
/// Initializes a new instance of the <see cref="HandleExceptionsAttribute"/> class.
/// </summary>
public HandleExceptionsAttribute() {
AspectPriority = 1;
}
public override void OnException(MethodExecutionArgs args) {
//Suppress the current transaction to ensure exception is not rolled back
using (var s = new TransactionScope(TransactionScopeOption.Suppress)) {
//Log exception
using (var exceptionLogContext = new ExceptionLogContext()) {
exceptionLogContext.Set<ExceptionLogEntry>().Add(new ExceptionLogEntry(args.Exception));
exceptionLogContext.SaveChanges();
}
}
}
}
[HandleExceptions]
public class YourClass {
}

Related

Using the Decorator Pattern to Conditionally Replace Behaviour Instead of Extending

Initially I had this structure:
interface IFileBackup
{
void Backup();
}
class BackUpMechanism1 : IFileBackup
{
void Backup()
{
//Back it up
}
}
class BackUpMechanism2 : IFileBackup
{
void Backup()
{
//Back it up in another way
}
}
class Client
{
//Instantiation of both mechanisms
//
try
{
backUpMechanism1.Backup();
}
catch(Exception ex)
{
backupMechanism2.Backup();
}
}
I was told that this was not a very clean design and to redesign it using the decorator pattern. The client should not know about the two back up mechanisms but just call backup and then the first mechanism should try to back up the file and if that fails then use mechanism 2. However I don't understand how to use the decorator pattern because from my understanding it extends functionality but doesn't replace functionality - which is what I want... How do I archive that? I have tried the following:
interface IFileBackup
{
void Backup();
}
class BackupMechanism1 : IFileBackup
{
public void Backup()
{
try
{
Console.WriteLine("Trying to back up to the cloud...");
throw new Exception();
}
catch(Exception ex)
{
Console.WriteLine("Oops that failed. We need to back up locally instead...");
}
}
}
class BackupMechanism2 : IFileBackup
{
IFileBackup _fileBackup;
public BackupMechanism2(IFileBackup fileBackup)
{
_filebackup = fileBackup;
}
public void Backup()
{
//All examples I have seen does this. But doesn't make sense in my case?
_fileBackup.Backup();
Console.WriteLine("Backing up locally");
}
}
//The client does not care about how the backup is done
class Client
{
static void Main()
{
//This is not right, but not sure what I should do in the client.
BackupMechanism2 localBackup = new BackupMechanism2(new BackupMechanism1());
localBackup.Backup();
Console.Read();
}
}
So essentially what I want to achieve is to have two backup mechanisms. Have the client just say backup I don't care how. Let the first mechanism try it's backup method if that fails then try the second method. I'm trying to use the decorator pattern to extend(replace) the backup behaviour of the first mechanism if it fails. I'm struggling to come up with a design that makes sense.
A very clean approach of implementing this would be adding a composite IFileBackup taking an array of IFileBackup objects, and trying them one by one until a working solution is found:
class CompositeBackup {
private readonly IFileBackup[] chain;
public CompositeBackup(params IFileBackup[] chain) {
this.chain = chain.ToArray();
}
public void Backup() {
foreach (var backup in chain) {
try {
backup.Backup();
return;
} catch {
continue;
}
}
throw new InvalidOperationException();
}
}
Now the client simply does this:
IFileBackup backup = new CompositeBackup(
new BackupMechanism1()
, new BackupMechanism2()
);
backup.Backup();
If you later decide to add BackupMechanism3 and BackupMechanism4, the user would need to add another object to the chain of backups. The rest of the code would remain unchanged. In addition, backup mechanisms themselves would remain unaware of other mechanisms' existence, which also simplifies the code.
The decorator pattern, in this case, can be used to provide fallback implementations. You can find plenty of obvious examples in the .Net streams implementation.
So with that in mind, your code should look something like this:
class abstract BaseFileBackup
{
internal BaseFileBackup Fallback;
internal BaseFileBackup(BaseFileBackup fallback) { Fallback = fallback; }
internal BaseFileBackup() { }
internal abstract void DoBackupWork();
internal void Backup()
{
try { DoBackupWork(); }
catch { if(Fallback != null) Fallback.Backup(); else throw; }
}
}
class BackUpMechanism1 : BaseFileBackup
{
internal BackUpMechanism1 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism1 (): base() {}
internal void DoBackupWork()
{
//Back it up
}
}
class BackUpMechanism2 : BaseFileBackup
{
internal BackUpMechanism2 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism2 (): base() {}
internal void DoBackupWork()
{
//Back it up in another way
}
}
// and to call it
class Client
{
static void Main()=>
new BackupMechanism2(new BackupMechanism1()).Backup();
}
Decorator Pattern is the WRONG choice in this scenario.
The problem that you are dealing with here is
under condition x call one method
under condition y call a different method
...
This is the precondition for the Strategy Pattern, and your initial solution was quite close to that. The problem in my mind is that you are using an Exception to determine the program flow, which is a BAD thing to do: exceptions cost stack space, and they should only be thrown under EXCEPTIONAL circumstances. Whereas in your case, it is expected that a given strategy will not work
IFileBackupStrategy
{
bool Backup(File fileToBackup);
}
IFileBackupContext
{
File ForBackup { set; }
bool Backup();
}
class CloudBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
class LocalBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
public class FileBackupContext : IFileBackupContext
{
private IEnumerable<IFileBackupStrategy> _backupStrategies
public Context(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public File ForBackup { set; private get; }
public bool Backup()
{
bool successFlag;
foreach(var strategy in _backupStrategies)
{
successFlag = strategy.Backup(ForBackup);
if(successFlag) break;
}
return successFlag;
}
}
In this case, all that the client needs to be aware of is the IFileBackupContext, and not the strategy employed to do the saving.
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
void SomeMethodThatInvokesBackingUp()
{
_context.ForBackup = new File(/* */);
if(!_context.Backup())
{
Console.WriteLine("Failed to backup the file");
}
}
}
The beauty of this design is that you can add more IFileBackupStrategy implementations, register them with your DI Container and voila they are instantly available to the client without a single code change or the need for re-compilation (though that will ultimately depend upon how you are populating your DI Container)
The decorator pattern is a method of adhering to the O principle in SOLID: which is
Open for extension and closed for modification
This means that you would use the decorator pattern to decorate an existing class, one that should not be changed and yet does not exhibit the behaviour required. The clue is in the name of the pattern: Decorator adds something, it does not change anything.
The Decorator Pattern is a Structural Pattern, whereas the Strategy Pattern, and what you are looking for, is a Behavioural Pattern
This example can be extended of course to report back the strategy which was ultimately employed, and also (if required) any reasoning for why alternate strategies were not.
Edited: in response to Blindy's comment below. Here is the paradigm for the decorator pattern, which should demonstrate how it is not the correct pattern for this problem:
class Image
{
void Render() { /* */ }
}
class FramedImage : Image
{
private Image _originalImage;
public FramedImage(Image original) => _originalImage = original;
new public void Render()
{
/* code to render a frame */
_originalImage.Render();
}
}
Image originalImage = new Image();
Image framedImage = new FramedImage(originalImage);
Image toRender = originalImage;
toRender.Render() // Renders the original image
toRender = framedImage;
toRender.Render(); // Renders the original image in a frame
It should be observed that there is no need to assign each Image to the toRender variable, that is done solely to demonstrate that a decorator is a decorated.
As you can see from this example, the decorator pattern adds behaviour, and it also invokes the decorated item's behaviour.
Edited: Further to the question posed by DSF below. Here is the full listing for a console app demonstrating how to achieve this using Unity 5.8.6
The code takes advantage of the new Tuple from C# 7.0.
I've just used some random number generation to determine whether or not each strategy implementation succeeds in performing its task.
using System;
using System.Collections.Generic;
using System.IO;
using Unity;
using Unity.Injection;
namespace StrategyPattern
{
public interface IFileBackupContext
{
FileStream ForBackup { set; }
(bool success, string strategy) Backup();
}
public interface IFileBackupStrategy
{
(bool success, string name) Backup(FileStream fileToBackup);
}
internal class LocalBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if(_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
return (_success, "LocalBackUp");
}
}
internal class CloudBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if (_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
fileToBackup.Close();
return (_success, "CloudBackUp");
}
}
public class FileBackupContext : IFileBackupContext
{
private readonly IEnumerable<IFileBackupStrategy> _backupStrategies;
public FileBackupContext(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public FileStream ForBackup { set; private get; }
public (bool success, string strategy) Backup()
{
foreach (var strategy in _backupStrategies)
{
var (success, name) = strategy.Backup(ForBackup);
if (success) return (true, name);
}
return (false, "");
}
}
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
public void BackgUpMyFile()
{
_context.ForBackup = new FileStream("d:\\myfile", FileMode.OpenOrCreate);
(bool success, string strategy) = _context.Backup();
if (!success)
{
Console.WriteLine("Failed to backup the file");
return;
}
Console.WriteLine($"File backed up using [{strategy}] strategy");
}
}
public class Bootstrap
{
private readonly IUnityContainer _container;
public Bootstrap()
{
_container = new UnityContainer();
_container.RegisterType<IFileBackupContext, FileBackupContext>();
_container.RegisterType<IFileBackupStrategy, LocalBackUp>("local");
_container.RegisterType<IFileBackupStrategy, CloudBackUp>("cloud");
_container.RegisterType<MyBackupClient>();
_container.RegisterType<Func<IEnumerable<IFileBackupStrategy>>>(new InjectionFactory(c =>
new Func<IEnumerable<IFileBackupStrategy>>(() =>
new[]
{
c.Resolve<IFileBackupStrategy>("local"),
c.Resolve<IFileBackupStrategy>("cloud")
}
)));
}
public MyBackupClient GetClient() => _container.Resolve<MyBackupClient>();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press ESC to quit ...");
Console.WriteLine("Press any other key to try again.");
Console.WriteLine();
var client = new Bootstrap().GetClient();
do
{
client.BackgUpMyFile();
} while (Console.ReadKey().Key != ConsoleKey.Escape);
}
}
}

Class Level Error Handler For DAO

I am using Entity Framework. Below is an example of a list method for an Actors context in my ActorsDao class. If you imagine my application is like imdb, there will be CRUD methods for various other contexts such as Movies, Directors, Genres, Reviews, Studios etc.
Regardless of the method or context, I handle errors in the same way. Due to my many methods across many contexts, my catch section is always exactly the same.
Obviously, I could create an error handling class, put the code in there, and just call a method in that class from the catch block.
However, I'm wondering if there a way to omit the TRY...CATCH from each method and set up a global error handler for the methods in my entity framework layer?
I would only want this global error handler to handle these errors and not errors from the rest of the application.
I seem to remember in Java Spring, you could annotate a class or method with the name of a method, and all errors would be passed to that without the need of a TRY...CATCH. I'm wondering if there is something similar for .NET (or a third party library with such functionality)?
public List<Actor> ListActors()
{
List<Actor> actorList = new List<Actor>();
using (var context = new ActorContext())
{
try
{
actorList = context.Actors.ToList<Actor>();
}
catch (Exception e)
{
//Handle error code
}
}
return actorList;
}
EDIT
I did some more research and found this code from here https://stackoverflow.com/a/4851985/1753877
private void GlobalTryCatch(Action action)
{
try
{
action.Invoke();
}
catch (ExpectedException1 e)
{
throw MyCustomException("Something bad happened", e);
}
catch (ExpectedException2 e)
{
throw MyCustomException("Something really bad happened", e);
}
}
public void DoSomething()
{
GlobalTryCatch(() =>
{
// Method code goes here
});
}
Would using a delegate like this be OK? It certainly meets my requirements.
You can create a class like this and extend the controller from this class.
Error Handler class looks like this :
package com.wes.essex.rest;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import com.wes.essex.bean.ErrorResponse;
public class SkyNewsController {
private static final Logger LOGGER = LoggerFactory.getLogger(SkyNewsController.class);
#ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleError(Exception ex) {
LOGGER.info("start");
LOGGER.error(ex.getMessage(), ex);
ErrorResponse error = new ErrorResponse();
error.setTimestamp(ZonedDateTime.now().format(DateTimeFormatter.ISO_INSTANT));
LOGGER.debug("error : {} ", error);
ResponseEntity<ErrorResponse> response = null;
if (ex instanceof ConstraintViolationException) {
error.setReasonCode(HttpStatus.BAD_REQUEST.value());
ConstraintViolationException constraintException = (ConstraintViolationException) ex;
Set<ConstraintViolation<?>> set = constraintException.getConstraintViolations();
String errorMessage = "Input Validation Failed:";
for (ConstraintViolation<?> constraintViolation : set) {
errorMessage += constraintViolation.getMessageTemplate() + ",";
}
errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
error.setErrorMessage(errorMessage);
response = new ResponseEntity<ErrorResponse>(error, HttpStatus.BAD_REQUEST);
} else {
error.setReasonCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setErrorMessage(ex.getMessage());
response = new ResponseEntity<ErrorResponse>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
return response;
}
}
This would be the baean class for error response :
package com.wes.essex.bean;
public class ErrorResponse {
private static final long serialVersionUID = 5776681206288518465L;
private String timestamp;
private String errorMessage;
private int reasonCode;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public int getReasonCode() {
return reasonCode;
}
public void setReasonCode(int reasonCode) {
this.reasonCode = reasonCode;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}

Catch derived class Exceptions in base class with different methods and arguments

I'm trying to make something like base "exception handler" thing. So this base class will try-catch exceptions when any method (with any number of parameters) in derived class gets invoked. I'm not good in describing this with words, so here is the scenario:
public abstract BaseClass
{
Exception _ex;
public Exception LastKnownException
{
get
{
return this._ex;
}
}
//...
//what do I do here to assign the value of above property when some random exception occur in derived class?
//...
//The closest I can get...
public void RunMethod(Action method)
{
try
{
method.Invoke();
}
catch (Exception ex)
{
this._ex = ex;
}
}
}
public class DerivedClass : BaseClass
{
public void DoRandomMethod(int couldBeOfAnyTypeHere, bool andIndefiniteNumberOfThese)
{
bool result = false;
var someObject = new OtherClass(couldBeOfAnyTypeHere, out andIndefiniteNumberOfThese);
someObject.DoInternalWork(result); // <-- here is where I need the base class to take care if any exception should occur
}
public int AnotherMethod(int? id)
{
if (!id.HasValue)
id = Convert.ToInt32(Session["client_id"]);
var someOtherObject = new OtherClassB(id.Value);
return someOtherObject.CheckSomething(); // <-- and catch possible exceptions for this one too
}
//The closest I can get... (see base class implementation)
public List<RandomClass> GetSomeListBy(int id)
{
RunMethod(() =>
string[] whateverArgs = new[] { "is", "this", "even", "possible?" };
YetAnotherStaticClass.GetInstance().ExecuteErrorProneMethod(whateverArgs); // <-- Then when something breaks here, the LastKnownException will have something
);
}
}
public class TransactionController : Controller
{
public ActionResult ShowSomething()
{
var dc = new DerivedClass();
dc.DoRandomMethod(30, true);
if (dc.LastKnownException != null)
{
//optionally do something here
return RedirectToAction("BadRequest", "Error", new { ex = dc.LastKnownException });
}
else
{
return View();
}
}
}
EDIT: My simple approach will work, only, I don't want to have to wrap all methods with this lambda-driven RunMethod() method all the time -- I need the base class to somehow intercept any incoming exception and return the Exception object to the derived class without throwing the error.
Any ideas would be greatly appreciated. And thanks in advance!
I think you should consider using the event System.AppDomain.UnhandledException
This event will be raised whenever an exception occurs that is not handled.
As you don't clutter your code with the possibilities of exception, your code will be much better readable. Besides it would give derived classes the opportunity to catch exceptions if they expect ones, without interfering with your automatic exception catcher.
Your design is such, that if someone calls several functions of your derived class and then checks if there are any exceptions the caller wouldn't know which function caused the exception. I assume that your caller is not really interested in which function causes the exception. This is usually the case if you only want to log exception until someone investigates them.
If that is the case consider doing something like the following:
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
if (ex != null)
logger.LogException(ex);
// TODO: decide whether to continue or exit.
}
If you really want to do this only for your abstract base class
public abstract BaseClass
{
private List<Exception> unhandledExceptions = new List<Exception>();
protected BaseClass()
{
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
}
private void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
if (ex != null)
this.UnhandledExceptions.Add(ex);
}
public List<Exception> LastKnownExceptions
{
get { return this.unhandledExceptions; }
}
I had a similar requirement for catching exceptions, but used a specific implementation (i.e. not an abstract class) to encapsulate the handling of errors.
Please note this takes in an argument for any expected exceptions (params Type[] catchableExceptionTypes), but of course you can modify to suit your own requirements.
public class ExceptionHandler
{
// exposes the last caught exception
public Exception CaughtException { get; private set; }
// allows a quick check to see if an exception was caught
// e.g. if (ExceptionHandler.HasCaughtException) {... do something...}
public bool HasCaughtException { get; private set; }
// perform an action and catch any expected exceptions
public void TryAction(Action action, params Type[] catchableExceptionTypes)
{
Reset();
try
{
action();
}
catch (Exception exception)
{
if (ExceptionIsCatchable(exception, catchableExceptionTypes))
{
return;
}
throw;
}
}
// perform a function and catch any expected exceptions
// if an exception is caught, this returns null
public T TryFunction<T>(Func<T> function, params Type[] catchableExceptionTypes) where T : class
{
Reset();
try
{
return function();
}
catch (Exception exception)
{
if (ExceptionIsCatchable(exception, catchableExceptionTypes))
{
return null;
}
throw;
}
}
bool ExceptionIsCatchable(Exception caughtException, params Type[] catchableExceptionTypes)
{
for (var i = 0; i < catchableExceptionTypes.Length; i++)
{
var catchableExceptionType = catchableExceptionTypes[i];
if (!IsAssignableFrom(caughtException, catchableExceptionType)) continue;
CaughtException = caughtException;
HasCaughtException = true;
return true;
}
return false;
}
static bool IsAssignableFrom(Exception exception, Type type)
{
if (exception.GetType() == type) return true;
var baseType = exception.GetType().BaseType;
while (baseType != null)
{
if (baseType == type) return true;
baseType = baseType.BaseType;
}
return false;
}
void Reset()
{
CaughtException = null;
HasCaughtException = false;
}
}

Unit testing exception property

I have exception
class SyntaxError : Exception {
public SyntaxError(int l) {
line = l;
}
public int line;
}
I'm using unit tests to test class Parser which on specific input should throw exception above. I'm using code like this:
[TestMethod]
[ExpectedException(typeof(Parser.SyntaxError))]
public void eolSyntaxError()
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
}
Is there any smart simple way to check if SyntaxError.line == 1?
Best I come up with is:
[TestMethod]
public void eolSyntaxError()
{
try {
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
Assert.Fail();
} catch (SyntaxError e) {
Assert.AreEqual(1, e.line);
}
}
I don't like it very much, is there better way?
Consider using FluentAssertions. Your test will then look like this:
[TestMethod]
public void eolSyntaxError()
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
Action parseEol = () => parser.eol();
parseEol
.ShouldThrow<SyntaxError>()
.And.line.Should().Be(1);
}
Otherwise, your approach is pretty much as good as it gets.
You could write a method similar to the one in NUnit
public T Throws<T>(Action code) where T : Exception
{
Exception coughtException = null;
try
{
code();
}
catch (Exception ex)
{
coughtException = ex;
}
Assert.IsNotNull(coughtException, "Test code didn't throw exception");
Assert.AreEqual(coughtException.GetType(), typeof(T), "Test code didn't throw same type exception");
return (T)coughtException;
}
And then you can use it in your test method
Parser.SyntaxError exception = Throws<Parser.SyntaxError>(() => parser.eol());
Assert.AreEqual(1, exception.line);
As per my comment, if the line at which you encounter the syntax error is relevant, then include it in your custom exception class, like so.
public class SyntaxError : Exception
{
public SyntaxError(int atLine)
{
AtLine = atLine;
}
public int AtLine { get; private set; }
}
Then it's easy to test.
EDIT - After having read the question (!) here's a simple additional Assert method which will tidy up your exception assertions.
public static class xAssert
{
public static TException Throws<TException>(Action a) where TException : Exception
{
try
{
a();
}
catch (Exception ex)
{
var throws = ex as TException;
if (throws != null)
return throws;
}
Assert.Fail();
return default(TException);
}
}
Usage as follows...
public class Subject
{
public void ThrowMyException(int someState)
{
throw new MyException(someState);
}
public void ThrowSomeOtherException()
{
throw new InvalidOperationException();
}
}
public class MyException : Exception
{
public int SomeState { get; private set; }
public MyException(int someState)
{
SomeState = someState;
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var subject = new Subject();
var exceptionThrown = xAssert.Throws<MyException>(() => { subject.ThrowMyException(123); });
Assert.AreEqual(123, exceptionThrown.SomeState);
}
}
I am not aware of an out of the box solution for this, but I have seen the concept of expectations which work like this:
[TestMethod]
public void EolSyntaxError()
{
Expectations.Expect<(SyntaxError>(
() =>
{
parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
parser.eol();
},
e =>
{
Assert.AreEqual(1, e.line);
});
}
Expectations needs to be implemented. I reckon there will be libraries out there which already do this. Anyhow, the Expect method in Expectations could look like this:
public static void Expect<TExpectedException>(
System.Action action,
System.Action<TExpectedException> assertion) where TExpectedException : Exception
{
if (action == null) { throw new ArgumentNullException("action"); }
try
{
action.Invoke();
Assert.Fail(string.Format("{0} expected to be thrown", typeof(TExpectedException).Name));
}
catch (TExpectedException e)
{
assertion.Invoke(e);
}
}

Fody Async MethodDecorator to Handle Exceptions

I am trying to use Fody to wrap all exceptions thrown from a method with a common exception format.
So I have added the required interface declaration and class implementation that looks like this :
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
[module: MethodDecorator]
public interface IMethodDecorator
{
void Init(object instance, MethodBase method, object[] args);
void OnEntry();
void OnExit();
void OnException(Exception exception);
void OnTaskContinuation(Task t);
}
[AttributeUsage(
AttributeTargets.Module |
AttributeTargets.Method |
AttributeTargets.Assembly |
AttributeTargets.Constructor, AllowMultiple = true)]
public class MethodDecorator : Attribute, IMethodDecorator
{
public virtual void Init(object instance, MethodBase method, object[] args) { }
public void OnEntry()
{
Debug.WriteLine("base on entry");
}
public virtual void OnException(Exception exception)
{
Debug.WriteLine("base on exception");
}
public void OnExit()
{
Debug.WriteLine("base on exit");
}
public void OnTaskContinuation(Task t)
{
Debug.WriteLine("base on continue");
}
}
And the domain implementation that looks like this
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
namespace CC.Spikes.AOP.Fody
{
public class FodyError : MethodDecorator
{
public string TranslationKey { get; set; }
public Type ExceptionType { get; set; }
public override void Init(object instance, MethodBase method, object[] args)
{
SetProperties(method);
}
private void SetProperties(MethodBase method)
{
var attribute = method.CustomAttributes.First(n => n.AttributeType.Name == nameof(FodyError));
var translation = attribute
.NamedArguments
.First(n => n.MemberName == nameof(TranslationKey))
.TypedValue
.Value
as string;
var exceptionType = attribute
.NamedArguments
.First(n => n.MemberName == nameof(ExceptionType))
.TypedValue
.Value
as Type;
TranslationKey = translation;
ExceptionType = exceptionType;
}
public override void OnException(Exception exception)
{
Debug.WriteLine("entering fody error exception");
if (exception.GetType() != ExceptionType)
{
Debug.WriteLine("rethrowing fody error exception");
//rethrow without losing stacktrace
ExceptionDispatchInfo.Capture(exception).Throw();
}
Debug.WriteLine("creating new fody error exception");
throw new FodyDangerException(TranslationKey, exception);
}
}
public class FodyDangerException : Exception
{
public string CallState { get; set; }
public FodyDangerException(string message, Exception error) : base(message, error)
{
}
}
}
This works fine for synchronous code. But for asynchronous code the exception handler is skipped, even though all the other IMethodDecorator are executed (like OnExit, and OnTaskContinuation).
For example, looking at the following test class :
public class FodyTestStub
{
[FodyError(ExceptionType = typeof(NullReferenceException), TranslationKey = "EN_WHATEVER")]
public async Task ShouldGetErrorAsync()
{
await Task.Delay(200);
throw new NullReferenceException();
}
public async Task ShouldGetErrorAsync2()
{
await Task.Delay(200);
throw new NullReferenceException();
}
}
I see that ShouldGetErrorAsync produces the following IL code :
// CC.Spikes.AOP.Fody.FodyTestStub
[FodyError(ExceptionType = typeof(NullReferenceException), TranslationKey = "EN_WHATEVER"), DebuggerStepThrough, AsyncStateMachine(typeof(FodyTestStub.<ShouldGetErrorAsync>d__3))]
public Task ShouldGetErrorAsync()
{
MethodBase methodFromHandle = MethodBase.GetMethodFromHandle(methodof(FodyTestStub.ShouldGetErrorAsync()).MethodHandle, typeof(FodyTestStub).TypeHandle);
FodyError fodyError = (FodyError)Activator.CreateInstance(typeof(FodyError));
object[] args = new object[0];
fodyError.Init(this, methodFromHandle, args);
fodyError.OnEntry();
Task task;
try
{
FodyTestStub.<ShouldGetErrorAsync>d__3 <ShouldGetErrorAsync>d__ = new FodyTestStub.<ShouldGetErrorAsync>d__3();
<ShouldGetErrorAsync>d__.<>4__this = this;
<ShouldGetErrorAsync>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<ShouldGetErrorAsync>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <ShouldGetErrorAsync>d__.<>t__builder;
<>t__builder.Start<FodyTestStub.<ShouldGetErrorAsync>d__3>(ref <ShouldGetErrorAsync>d__);
task = <ShouldGetErrorAsync>d__.<>t__builder.Task;
fodyError.OnExit();
}
catch (Exception exception)
{
fodyError.OnException(exception);
throw;
}
return task;
}
And ShouldGetErrorAsync2 generates :
// CC.Spikes.AOP.Fody.FodyTestStub
[DebuggerStepThrough, AsyncStateMachine(typeof(FodyTestStub.<ShouldGetErrorAsync2>d__4))]
public Task ShouldGetErrorAsync2()
{
FodyTestStub.<ShouldGetErrorAsync2>d__4 <ShouldGetErrorAsync2>d__ = new FodyTestStub.<ShouldGetErrorAsync2>d__4();
<ShouldGetErrorAsync2>d__.<>4__this = this;
<ShouldGetErrorAsync2>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<ShouldGetErrorAsync2>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <ShouldGetErrorAsync2>d__.<>t__builder;
<>t__builder.Start<FodyTestStub.<ShouldGetErrorAsync2>d__4>(ref <ShouldGetErrorAsync2>d__);
return <ShouldGetErrorAsync2>d__.<>t__builder.Task;
}
If I call ShouldGetErrorAsync, Fody is intercepting the call, and wrapping the method body in a try catch. But if the method is async, it never hits the catch statement even though the fodyError.OnTaskContinuation(task) and fodyError.OnExit() are still called.
On the other hand, ShouldGetErrorAsync will handle the error just fine, even though there is no error handling block in the IL.
My question is, how should Fody be generating the IL to properly inject the error block and make it so async errors are intercepted?
Here is a repo with tests that reproduces the issue
You are only placing the try-catch around the content of the 'kick-off' method, this will only protect you up to the point where it first needs to reschedule (the 'kick-off' method will end when the async method first needs to reschedule and so will not be on the stack when the async method resumes).
You should look at modifying the method implementing IAsyncStateMachine.MoveNext() on the state machine instead. In particular, look for the call to SetException(Exception) on the async method builder (AsyncVoidMethodBuilder, AsyncTaskMethodBuilder or AsyncTaskMethodBuilder<TResult>) and wrap the exception just before passing it in.
await sure makes asynchronous methods look simple, doesn't it? :) You just found a leak in that abstraction - the method usually returns as soon as the first await is found, and your exception helper has no way to intercept any later exceptions.
What you need to do is implement both the OnException, and handle the return value from the method. When the method returns, and the task isn't completed, you need to wind up an error continuation on the task, which needs to handle exceptions the way you want them to be handled. The Fody guys thought of that - that's what the OnTaskContinuation is for. You need to check the Task.Exception to see if there's an exception lurking in the task, and handle it however you need to.
I think this will only work if you want to rethrow the exception while doing logging or something - it does not allow you to replace the exception with something different. You should test that :)

Categories

Resources