AOP with Autofac and DynamicProxy2 Exception Handling - c#

I'm trying to centrally manage Exception handling for a certain method but I can't seem to get there.
public class ExceptionInterceptor : IInterceptor
{
private readonly Logger _logger;
public ExceptionInterceptor(Logger logger)
{
_logger = logger;
Measure.Configure(new StatsdConfig());
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
//if ((Task<System.Threading.Tasks.VoidTaskReturn>) invocation.ReturnValue.Status == "Failed")
//{
// throw new Exception(invocation.ReturnValue.Exception[0]);
//}
}
catch (Exception e)
{
var errorMessage =
String.Format(
"An error occurred while retrieving fund data. Error Message: {0} Inner Exception: {1}",
e.Message, e.InnerException != null ? e.InnerException.Message : "<None>");
_logger.Log(errorMessage);
Measure.Counter("Exception", 1);
Measure.Event("Exception", errorMessage);
throw;
}
}
I'm wiring this up in a module like so:
builder.RegisterType<DataConsumer>().
As<IConsumer<DataRequest>>().
EnableInterfaceInterceptors().
InterceptedBy(typeof(ExceptionInterceptor));
builder.RegisterType<ExceptionInterceptor>().AsSelf();
var loggingInterceptor = new LoggingInterceptor(Logger);
builder.Register(c => loggingInterceptor);
However when I throw an exception in the method invocation this doesn't bubble up to the interceptor as an exception thrown, so it never enters the catch block.
Is there any way to catch the intercepted method's exception in the interceptor?
I also can't access the invocation.ReturnValue.Status for some reason and as such can't test whether there was a thrown exception in order to re-throw.
Can anyone shed some light into what I might nor be doing right here?
Ta

I'm having a difficult time reproducing your issue due to a bit of incomplete information. For example, you noted that the IConsumer<T> interface is a MassTransit interface, but the interface in MassTransit isn't generic. It also specifically mentions that the interface is supposed to be a marker just for IoC containers, which may have some implications on your wire-up.
First, let's post a working exception handling example. To be self-contained, I'll create an IWorker<T> interface in place of IConsumer<T> and a simple implementation:
public interface IWorker<T>
{
bool DoWork(T message);
}
public class StringWorker : IWorker<string>
{
public bool DoWork(string message)
{
throw new DivideByZeroException();
}
}
Now I'll create a simple exception logger that just pipes info to the console.
public class ExceptionLogger : IInterceptor
{
private readonly TextWriter _output;
public ExceptionLogger(TextWriter output)
{
_output = output;
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch(Exception ex)
{
_output.WriteLine("Logged Exception: {0}", ex.Message);
throw;
}
}
}
I can then wire it up and see it in action like this:
var builder = new ContainerBuilder();
builder.RegisterInstance(Console.Out).As<TextWriter>();
builder.RegisterType<ExceptionLogger>();
builder.RegisterType<StringWorker>()
.As<IWorker<string>>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(ExceptionLogger));
var container = builder.Build();
var worker = container.Resolve<IWorker<string>>();
worker.DoWork("Test!");
When I run this, I see on the console just before the program dies (with the unhandled exception - note my handler didn't swallow it, just logged it):
Logged Exception: Attempted to divide by zero.
So it's working.
I think there's more in your environment that may be causing trouble here. It could be something you think is unrelated but is actually important.
General things to investigate:
Temporarily update your DataConsumer to throw an exception immediately inside one of the interface methods. After building your container, resolve a, IConsumer<DataRequest> and call that interface method. Does it get logged?
Look at the places that you're expecting to see logging occur. Are you resolving and working with IConsumer<DataRequest> or something else? It's wrapping the interface methods, not the object type, so not all methods are covered.
Set a breakpoint in the interceptor and see if any invocation at all is passing through it. It won't catch exceptions if it's not being hit. :)
Check to see if there's any other exception handling policies or code in action. For example, some folks use the Enterprise Library exception handling block to deal with exceptions and that may be interfering with your work here.
I've not used MassTransit, but check to see if there's any other object proxying going on. (Doubtful, but I know I've run into this with products like Glimpse, so you end up with proxies wrapped around proxies, which becomes challenging.)
Is the exception actually happening in the place you think it is? It may be happening and getting handled somewhere that isn't wrapped with the proxy.
Basically, reduce the working pieces to the smallest set possible until you can see it working, then slowly expand until you find the place it breaks down. I don't know if any of these apply to your situation, but these are the things I'd start looking at if I was troubleshooting.
But... exception handling in an AOP fashion using interceptors does work, so it's something else going on that's causing the challenge.

It seems that it isn't possible for the exception thrown in the target proxy to be pushed up to the interceptor, and as such what I was trying to do didn't work. I ended up handling the exceptions at the class they occur.
Disappointed I didn't manage to get this to work the way I was intending to.

Related

How to log exceptions with structured arguments in .NET Core

I can't find a consistent way to log exceptions in my .NET Core microservice.
Informational messages logging guidelines are simple (Microsoft.Extension.Logging is used):
_logger.LogInformation($"Reading file {path}..."); // bad
_logger.LogInformation("Reading file {Path}...", path); // good
The benefit of the second variant is structured information: by using a clever log event router (like Serilog with RenderedCompactJsonFormatter) the path is written as separate property of the log event.
Things are going worse with errors logging. The requirements are obvious:
Errors are implemented as exceptions.
An error is logged in the catch block where it is handled.
Each error is logged in a structured form.
So, I'd expect the error reporting to look like
throw new MyException("Failed to read file {Path}", path);
and error logging - like
catch(MyException e)
{
_logger.LogError(e, "Processing error");
}
LogError method here logs the complete error description, but it is not structured: the path is not added as a property.
I tried to make MyException hold the message template and the arguments, but there are 2 problems with this approach:
How to render the exception message based on a template with named arguments?
An argument may be disposed when an exception is processed in a catch block.
Please tell me how you deal with this.
Exceptions in .NET don't support structured parameters like that. Since you are using custom exceptions, you could add this functionality to your own exception class.
For example:
public class MyException : Exception
{
public object[] Props { get; }
public MyException()
{
}
public MyException(string message)
: base(message)
{
}
// Add custom "props" parameter to your exception class
public MyException(string message, params object[] props)
: base(message)
{
Props = props;
}
public MyException(string message, Exception inner)
: base(message, inner)
{
}
}
Now in your code you could do something like this:
try
{
var file = "image.png";
var path = "./my/path/";
throw new MyException("Failed to read file '{file}' in path '{path}'", file, path);
}
catch (MyException e)
{
_logger.LogError(e, e.Message, e.Props);
}
If you look at your logs (I'm using InvisionLog here), then you should see that it is structured.
I think this is the only way to catch your exceptions and log them in a structured manner.

Exception handling in asp net core

I'm looking for some guidance on how to best handle exceptions in asp net core. Based on these docs from microsoft I've setup the UseStatusCodePagesWithRedirects middleware. This works for things such as 404's. However for API requests within my code that return exceptions this doesn't work. So following this doc I've setup an exception filter. This kinda works and this is where I'm looking for help.
I have the following code in a class library so it can be re used elsewhere. A mini wrapper for my api. I'm using Flurl to construct the request. My viewModelBuilder calls GetAll.
public async Task<List<TableDto>> GetAll(int branchId)
{
var result = await _baseUrl.AppendPathSegment("/v1/Table/GetAll").WithOAuthBearerToken(await _authenticationManager.GetToken()).GetJsonAsync<List<TableDto>>();
return result;
}
If GetAll throws an exception then the following exception filter comes into play.
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
// ex.Call.Response.StatusCode // This works with the original exception but not here
if (context.HttpContext.Response.StatusCode == (int)HttpStatusCode.Forbidden)
{
// Always 200
}
}
}
I would like to do different things based on the exception status code. So for a 401 or 404 I would like to show an access denied screen or a login screen and then for other errors maybe just a general error screen. However context.HttpContext.Response.StatusCode is always 200.
Is this the right way to go about doing this? The error handing documentation suggests that middleware is better but I'm not sure if its referring to this use case as I could only get it working for 404s.
How do I get the correct status code in a exception filter?
I know that if I put a try catch around the original GetAll as below
try
{
var result = await _baseUrl.AppendPathSegment("/v1/Table/GetAll").WithOAuthBearerToken(await _authenticationManager.GetToken()).GetJsonAsync<List<TableDto>>();
return result;
}
catch (FlurlHttpException ex)
{
if (ex.Call.Response != null)
{
if (ex.Call.Response.StatusCode == HttpStatusCode.Forbidden)
{
throw new ForbiddenException();
}
}
}
then in the exception filter I can do the following
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
if (context.Exception is ForbiddenException)
{
}
}
}
and then I can do specific things for specific exceptions however thing means I have to try catch every call and voids the point of the global exception filter. Any advice would be appreciated.
Thanks
M
EDIT
Based on this answer here I could write a custom middleware and I quickly did that but I'm still stuck with the same problem of not being able to check for a 401 or 403 and only being able to get access to custom exceptions that have been throw. If I can access the status code then I think both solutions will work

Exception Handling : AOP vs Classic Handling?

I'm upgrading a Plugin Loading Engine (.NET) which does the following :
Loads Plugins
Connects them to the appropriate Data Source
Launchs the Plugins
Displays the results
All the plugins implement the same Interface : IPluginand each one is launched in a separate BackGroundWorker. All the BackgroundWorkers are managed by a module called Host.
My problem is the Errors/Exceptions Handling. The engine is already deployed and I want to find an elegant way to handle the Errors/Exceptions that could be thrown when the plugins run. Some Exceptions are caught in the plugins but not all of them.
I was thinking about a separate layer that could catch the errors and treat them for all the plugins.
I imagined a kind of Context attached to each Plugin which contain its progress level (BackgroundWorker.ReportProgress), its status, the thrown exceptions(using the RunWorkerCompletedEvent) but the errors are thrown only after the BackgroundWorker stops. I would like to interrupt it when an exception is thrown.
I was also thinking that Aspect Oriented Programming could be a great way. I took a look on the net and found some framework like Spring.NET. But not sure if it could be appropriate in my case.
[UPDATE]
Here are more design details as requested :
IPlugin Interface : Called AbstractEnvChecker :
The application is a Rich Client App. After compiling the plugins, the generated DLL are loaded and a List is displayed to the users in a simple Windows Form. The user selects then the plugins to launch and the Plugin.DoWork() method is called.
And here is how the Host launches the selected Plugins :
void LaunchPlugin(AbstractEnvChecker p_Plugin)
{
if (p_Plugin != null)
{
BackgroundWorker l_BackgroundWorker = new BackgroundWorker();
l_BackgroundWorker.WorkerReportsProgress = true;
l_BackgroundWorker.WorkerSupportsCancellation = true;
l_BackgroundWorker.DoWork +=
new DoWorkEventHandler(bw_DoWork);
l_BackgroundWorker.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
l_BackgroundWorker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
m_PluginByThreadMap.Add(l_BackgroundWorker, p_Plugin);
l_BackgroundWorker.DoWork += p_Plugin.DoWork;
l_BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(l_BackgroundWorker_RunWorkerCompleted);
l_BackgroundWorker.RunWorkerAsync(p_Plugin);
}
}
Is AOP an appropriate solution to add the Error Handling Layer ?
The simplest way would be to just wrap the IPlugin.DoWork() method in a try/catch clause. something like this:
l_BackgroundWorker.DoWork += (o, e) => ExecutePlugin(o, e, p_plugin);
private void ExecutePlugin(object sender, DoWorkEventArgs e, IPlugin plugin)
{
try
{
plugin.DoWork(o, e);
}
catch (Exception e)
{
//do something with the error. disable the plugin maybe?
}
}
If this work then using Spring just for the Error handling is a bit overkill in my opinion.
Something additional you could do is throwing a custom exception (e.g. a PluginException) and handle those globally in your Application, this can be achieved by attaching to:
Application.ThreadException and AppDomain.CurrentDomain.UnhandledException events
Spring.net uses dynamic weaving, which basically means that at runtime Spring.net aop can wrap exception handlers around method calls. But Spring.net aop needs a seam to position it's interceptor in.
If your plugins should be loaded into a UI, then the user (probably) can invoke methods that don't go through the host or IPlugin interface at all, making it hard (if not impossible) for spring.net aop to intercept and wrap exception handlers.
If your host is a console application or service that calls myPlugin.DoWork(), then it's definitely possible to intercept any exceptions thrown by the plugin using Spring.net aop. If you could provide a bit more detail (see comments to your question) then I can show you how to do this.
Below an example that uses Spring.net AOP to proxy a plugin instance and wrap it with an interceptor, that catches a thrown exception and delegates it back to the host. Note that you can do this without AOP too ... that's up to you.
using System;
using AopAlliance.Intercept;
using NUnit.Framework;
using Spring.Aop.Framework;
namespace Aop
{
[TestFixture]
public class SimpleProxyFactoryTests
{
[Test]
public void Main()
{
var host = new Host();
var mp = new SimplePlugin();
var pf = new ProxyFactory(mp);
pf.AddAdvice(new DelegateToHostExceptionHandlingAdvice(host));
var proxy = (IPlugin)pf.GetProxy();
proxy.DoWork();
}
}
public interface IPlugin
{
void DoWork();
}
public class Host
{
public void HandleExceptionFromPlugin(Exception ex)
{
Console.WriteLine("Handling exception: {0}", ex.Message);
}
}
public class SimplePlugin : IPlugin
{
public void DoWork()
{
Console.WriteLine("Doing it and throwing an exception ... ");
throw new ApplicationException("Oops!");
}
}
public class DelegateToHostExceptionHandlingAdvice : IMethodInterceptor
{
private readonly Host _host;
public DelegateToHostExceptionHandlingAdvice(Host host)
{
_host = host;
}
public object Invoke(IMethodInvocation invocation)
{
try
{
return invocation.Proceed();
}
catch (Exception ex)
{
_host.HandleExceptionFromPlugin(ex);
return null;
}
}
}
}
Discussion
I hope I've shown you how you could leverage an aop framework to do exception handling. As Sebastian mentions in his answer, using Spring aop only for exception wrapping might be considered overkill - and I agree; compare the simplicity of his code example to the complexity of mine. Imagine explaining either one to a new developer on your team.
Spring aop starts to "shine" when you use it in combination with the Spring IOC container.

log all handled exception using log4net + AutoFac interceptor

I'm using Log4Netto log my application. currently I want to log every methods enter in my app (for testing purpose). Therefor I'm using AutoFac interception capabilities, somethong like this:
builder.Register(c=> new MyClass()).As<IMyInterface>().EnableInterfaceInterceptors().InterceptedBy(typeof(LoggerClass));
builder.Build();
and my LoggerClass looks something like this:
public class LoggerClass : StandartInterceptor
{
ILog _log = LogManager.GetLogger(typeof(LoggerClass));
override void PreProceed(IInvocation invovation)
{
_log.Info(string.Format("entering method: {0}",invocation.Method.Name);
}
}
for now this implementation will print message for all method invocation (the interceptor catches all methods entries).
Question
I would like to use this interception mechanism to log every handled Exception.
For example instead of coding this:
catch (myException ex)
{
_log.Error(string.Format("catches exception {0}", ex.Message));
}
I'll have extra method in my LoggerClass that will wrap the catch statement and inject to it log message.
Is there any way to do it using Log4Net? since basically the interceptor work around the method, and I need it to work inside method.
On your caught exceptions, you will never enter into the catch block of your interceptor.
Therefore, in your method when you catch an exception, you can handle the caught exception in an additional intercepted method that will get logged appropriately. This will inflate your codebase a bit, but you will end up getting the information you want without sacrificing your architecture.
public void InterceptedMethod()
{
try
{
//Some code that fails.
}
catch
{
HandleException();
}
}
//Intercept this method also
public void HandleException()
{
}

Unit testing WCF Faults

What's the best way to unit test expected faults from WCF services?
I am attempting to unit test a WCF service which is (correctly) throwing FaultExceptions for a certain reproducible error. The unit tests get an instance of the WCF client and call the applicable service method, which throws a FaultException.
All of that works as you would expect, but I am having difficulty unit testing this, because the fault causes the IDE to break when the error isn't caught in the service implementation. Because I am using faults, and not exceptions, I was expecting the IDE to serialize the exception and send it to the client, where it would raise an exception.
I do see that there is a configuration option to disable breaking for specific user-unhandled exceptions, but I was hoping somebody could point out a better way to achieve the same results, as this isn't easily doable in a team environment.
Here's some sample code of what the implementation currently looks like...
The unit test project has a service reference to my WCF service, and I have defined the interface as such:
[OperationContract(Name = "DoSomething")]
[FaultContract(typeof(EpicFail))]
ResponseObject DoSomething(RequestObject requestObject);
The fault is defined as such:
[DataContract]
public class EpicFail
{
public EpicFail(string action)
{
this.Reason = "Epic Fail";
this.Action = action;
}
[DataMember]
public string Reason
{
get;
set;
}
[DataMember]
public string Action
{
get;
set;
}
}
The code that calls the service looks vaguely like this:
[TestMethod()]
[ExpectedException(typeof(FaultException<EpicFail>))]
public void FaultTest_Fails_Epicly()
{
bool testPassed = false;
try
{
ResponseObject resp = GetServiceClient().DoSomething(req);
}
catch (FaultException<EpicFail>)
{
testPassed = true;
}
Assert.IsTrue(testPassed);
}
I edited the code to show that I am using the ExpectedException attribute and it doesn't seem to be having much effect on keeping the IDE/Debugger from breaking when the exception is thrown in the service.
You can always use ExpectedExceptionAttribute (in NUnit) to make sure this is the exception thrown. MSTest has similar concept as well.
[ExpectedException(typeof(MyException))]
void my_test()
{
// test
}
If you have some Mock verification to do, I would use try/catch block and verify in the catch and then throw the exception.
UPDATE
When you are using ExpectedException attribute, you are not supposed to catch the exception, instead you need to let the NUnit that runs your test to catch it.
If you need to verify special information in the exception then you catch the exception, verify the information and then rethrow:
[ExpectedException(typeof(MyException))]
void my_test()
{
try
{
// call the service
}
catch(MyException ex)
{
Assert.IsTrue(ex.Message.Contains("error code 200"));
throw ex;
}
}
mattv,
Why does this test has to access the service remotely? From what I see your code:
ResponseObject resp = GetServiceClient().DoSomething(req);
Is somehow getting a service client, and not a service instance itself. I'd advise to test the service concrete class directly for unit tests.
However, if you need this scenario, have you tried NOT CATCHING the exception and running the test? Does it give the same result?
And by the way, if you need to catch and rethrow use the following pattern:
try {
//Do something
}
catch(SomeException e) {
//Do something with e
throw
}

Categories

Resources