Lately I am working on exception logging module of a WCF service. Unfortunately the service hasn't been introduced with unit tests, therefore there are many unexpected exceptions occurring. And so far I have accomplished to get the exceptions with interceptor aproach, by implementing IErrorHandler interface and tying it to the service interface with IServiceBehaviour. I liked this functionality very much actually. But it brought me into a next step of desire of getting the details of exception. Like on which line did the exception occurred?
I can satisfy this desire by 2 ways in my mind:
By having a variable for keeping track of the lines I've passed through successfully, and including it in the exception thrown.
By catching exceptions from all lines seperately.
But both approaches seem very lousy to me. I am wondering is there a known design pattern or a tool to achive this goal?
In my opinion you might try using logging, such as log4net. Then you can find out where is and what happened. Exception object not always contains the stack info, because of "inlining", that occur during optimization etc.
include the PDB files for your service and the line numbers will be included in exception.ToString()
The way we have solved this problem is twofold:
Our services are dumb wrappers around commands. So when a service method is entered it delegates its work to a command.
We wrap every command call in a logging proxy that is responsible for logging input, output and errors and executing the command.
For example:
public FooServiceModel GetFoo(int fooId)
{
return new ILogged<GetFooCommand>().Target.Execute(fooId);
}
This delegates execution of the command to ILogged which:
Logs the command name
Logs the command parameters
Logs the execution result
Logs any exceptions
It also does some other stuff to link up the client request with the server call using custom message headers so that a call can be completely debugged from client to server and back. This is incredibly useful and allows us to diagnose even complex problems off site.
We use the Castle.Core dynamic proxy to implement ILogged with an interceptor that looks something like this (ILog is a log4net logger):
public class LoggingInterceptor : IInterceptor
{
public LoggingInterceptor([NotNull] object target, [NotNull] ILog logger)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
this.Target = target;
this.Logger = logger;
}
public object Target { get; set; }
public ILog Logger { get; set; }
public void Intercept(IInvocation invocation)
{
try
{
this.Logger.Debug(invocation);
invocation.ReturnValue = invocation.Method.Invoke(
this.Target, invocation.Arguments);
this.Logger.Debug("Invocation return value:");
this.Logger.Debug(invocation.ReturnValue);
}
catch (TargetInvocationException ex)
{
this.Logger.Error("Unable to execute invocation", ex);
if (ex.InnerException != null)
{
throw ex.InnerException;
}
throw;
}
}
}
The invocation itself is rendered by a custom log4net object renderer:
public class InvocationRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
var invocation = (IInvocation)obj;
var builder = new StringBuilder();
builder.AppendFormat(
"Invoking Method: {0} --> '{1}' with parameters (",
invocation.Method.DeclaringType != null
? invocation.Method.DeclaringType.FullName : "{Unknown Type}",
invocation.Method);
var parameters = invocation.Method
.GetParameters()
.Zip(invocation.Arguments, (p, a) => new { Parameter = p, Argument = a })
.ToArray();
var index = 0;
foreach (var parameter in parameters)
{
builder.AppendFormat(
"{0}: {1}",
parameter.Parameter.Name,
rendererMap.FindAndRender(parameter.Argument));
if (++index < parameters.Length)
{
builder.Append(", ");
}
}
builder.Append(")");
writer.Write(builder.ToString());
}
}
Hopefully that will give you some ideas on how to tackle this problem.
Related
I am currently adding some logging to our application to aid debugging in the future. To achieve this I have written a DLL with a static class which basically acts as a layer between our application and writes to the chosen log source, this is normally application insights.
One of the things I want to achieve is to log a trace to application insights with the method name and parameters, now this is achievable with code like this:
var methodName = MethodBase.GetCurrentMethod().Name;
var methodParameters = new Dictionary<string, string> { { "Parameter1", "Parameter1 Value" }, { "Parameter2", "Parameter2 Value" } };
appInsightsClient.TrackTrace(methodName, methodParameters);
and this works fine.
I am wondering if there is a better / cleaner way to achieve this? For methods with lots of parameters this will easily become difficult to read. I know that MethodBase.GetCurrentMethod() has a method for GetParameters() but these do not return the value. This is also relies on the developer setting the methodParameters / methodName variables back to null so they are picked up by garbage collection and with lots of methods being hit, I don't want to consume too much memory.
I appreciate this question is partly subjective and the opinion of the individual developer, but I can't seem to find any alternatives or examples out there, and can't be the only person who does this.
One way to solve it is using an AOP framework. I know at least a couple of them. One is PostSharp, which is really feature rich but isn't free. The other one I've experience with is MrAdvice.
Basically what you can do with those framework is create method interception points. You can apply custom logic when a method is entered and exited. What you could do is inspect the method info and use that in the logging. You can decorate the methods you are interested in so you have control over which methods are logged or not logged.
For example, using MrAdvice you can do something like:
public sealed class AppInsightsRequestAttribute : Attribute, IMethodAsyncAdvice
{
private static readonly TelemetryClient TelemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
public async Task Advise(MethodAsyncAdviceContext context)
{
var parameters = context.TargetMethod.GetParameters();
var parameterDescription = string.Join(", ",
parameters.Select(p => $"{p.ParameterType.Name} {p.Name}"));
var signature = $"{context.Target ?? context.TargetType}.{context.TargetName}({parameterDescription})";
using (var operation = TelemetryClient.StartOperation<RequestTelemetry>(signature))
{
try
{
await context.ProceedAsync();
}
catch (Exception)
{
operation.Telemetry.Success = false;
throw;
}
finally
{
EnrichRequestTelemetry(operation.Telemetry, context, parameters);
}
}
}
private static void EnrichRequestTelemetry(ISupportProperties telemetry, MethodAsyncAdviceContext context, IReadOnlyList<ParameterInfo> parameters)
{
telemetry.Properties.Add(
new KeyValuePair<string, string>("Accessibility",
context.TargetMethod.Attributes.ToVisibilityScope().ToString()));
for (var i = 0; i < context.Arguments.Count; i++)
{
telemetry.Properties.Add($"ARG {parameters[i].Name}", context.Arguments[i].ToString());
}
}
}
This code will create a RequestTelemetry item and send it to application insights. The EnrichRequestTelemetry method will add the method arguments and values as custom properties to the item.
You can then decorate your methods like this: (there are more options, but this is to demonstrate a possibility)
public class SomeClass
{
[AppInsightsRequest]
public async Task<string> SayHello(string to)
{
var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
string response = null;
try
{
var greeting = $"Hello {to}";
telemetryClient.TrackTrace($"Sending {greeting}");
response = await SomeService.SendAsync(greeting);
}
catch (Exception exception)
{
telemetryClient.TrackException(exception);
}
return response;
}
}
A complete sample using a console application to send telemetry to application insights can be found in this repository which I created.
Scenario
I have a .NET Core 2.2 web API with an exception handling middleware. Whenever an exception occurs in the application (inside the MVC layer) it gets caught by the exception middleware and returned as an internal server error back to the frontend and logged to kibana.
The problem
This is all fine and well when things go wrong, but sometimes I want to notify the calling application of specifically what went wrong. I.e., "Could not find record in database!" or "Failed to convert this to that!"
My Solution
I've used application Exceptions (not great - I know) to piggy back off the error middleware to return this to the frontend. This has been working fine, but has created a lot of noise around the code by having to throw a whole bunch of exceptions. I'm not satisfied with this approach and convinced that there must be a better solution.
My application architecture: I'm following a traditional n-tier application layout being services (business logic) and repositories (DAL) all speaking to each other. I would preferably like to elegantly bubble up any issues back to the user in any of these layers.
I've been thinking about this for a while now and am not sure what the best way to go about it is. Any advice would be appreciated.
I use a kind of the operation result pattern (non-official pattern).
The principle is to return a new Type containing:
Whether the operation was a success.
The result of the operation if was successful.
Details about the Exception that caused the failure.
Consider the following class:
public class OperationResult
{
protected OperationResult()
{
this.Success = true;
}
protected OperationResult(string message)
{
this.Success = false;
this.FailureMessage = message;
}
protected OperationResult(Exception ex)
{
this.Success = false;
this.Exception = ex;
}
public bool Success { get; protected set; }
public string FailureMessage { get; protected set; }
public Exception Exception { get; protected set; }
public static OperationResult SuccessResult()
{
return new OperationResult();
}
public static OperationResult FailureResult(string message)
{
return new OperationResult(message);
}
public static OperationResult ExceptionResult(Exception ex)
{
return new OperationResult(ex);
}
public bool IsException()
{
return this.Exception != null;
}
}
Then you could easily adapt OperationResult or create a class that inherits from OperationResult, but uses a generic type parameter.
Some examples:
The Operation Result Pattern — A Simple Guide
Error Handling in SOLID C# .NET – The Operation Result Approach
As per the Microsoft's standards, it is ideal to use ProblemDetails object in case of 4xx/5xx exceptions -
Following is the customised RequestDelegate method which you can use in ApiExceptionHandler to handle exceptions.
public async Task RequestDelegate(HttpContext context)
{
var exception = context.Features.Get<IExceptionHandlerFeature>().Error;
var problemDetails = new ProblemDetails
{
Title = "An unexpected error occurred!",
Status = GetStatusCode(exception),
Detail = _env.IsDevelopment() ? exception.Message : "An unexpected error occurred!",
Instance = $"{Environment.MachineName}:{context.TraceIdentifier}:{Guid.NewGuid()}"
};
_logger.LogError($"Exception thrown. StatusCode: {problemDetails.Status}. Instance: {problemDetails.Instance}", exception);
context.Response.StatusCode = problemDetails.Status.Value;
context.Response.WriteJson(problemDetails, "application/problem + json");
await Task.CompletedTask;
}
Objective is to unit test a PUBLIC VOID Method.
I have a mocked service, which my class-under-test would call, in a for-each loop with 3 different parameters.
The class-under-test passes some input parameters to "SendRequest" method of the service which executes using those parameters.
I want the mocked service to throw an exception when one of the parameters has a specific value e.g "abc".
I use something like this:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
//do some logging and continue calling service with next item in list
}
}
}
}
var myService = new Mock<IMyService>();
myService.Setup(x => x.SendRequest("abc")).Throws<Exception>();
myService.Setup(x => x.SendRequest("aaa"));
myService.Setup(x => x.SendRequest("bbb"));
var classUnderTest = new ClassUnderTest(myService.Object);
classUnderTest.MyMethod();
myService.Verify(x =>x.SendRequest(It.IsAny<string>()), Times.Exactly(2));
More Context:
As MyMethod returns void, to test it, I can only rely on the the fact that my dependencies were invoked at different portions of the code in this method. For e.g. if there is a null check for input parameters before service call, the method would return before it invokes the service. If it goes past null check, the dependency service would be invoked. I would be able to trace these in the code coverage results( and in debug mode).
When I run the test, it fails because its invoking the service thrice but I expect the invocation to happen twice(now may be I am wrong and may be that although it is supposed to throw exception the invocation attempt is still counted by Verify call and hence I get 3 runs).
Whatever be the case, on debug I see that the service never throws exception. I have a try-catch in the for-each-loop where I want to do some logging and continue calling the service again with the next value. But I never get to get inside the Catch block.
What am I doing wrong?
Option 1: Specific Exception
My 1st suggestion would throw a more specific exception so you can be more sure.
Option 2: Inject an ILogger service
Refactor out the logging into an ILogger and inject that in. Then pass a mock of that in and assert against it.
Option 3: Extract and Override
If you must check catch block was hit you can use extract and override:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
LogError(ex);
}
}
}
protected virtual LogException(Exception ex)
{
//do logging
}
}
public class TestableClassUnderTest : ClassUnderTest
{
public bool LoggingWasCalled { get; set; }
protected virtual LogException(Exception ex)
{
LoggingWasCalled = true;
}
}
Then you could sheck something like this:
var testableSut = new TestableClassUnderTest ();
testableSut.MyMethod("abc");
Assert.True(testableSut.LoggingWasCalled);
I walk through it in more detail here: http://devonburriss.me/testing-the-untestable/
My DAL doesn't handle exceptions and it will be propagated up to the calling method in the presenter classes where the exception will be handled.
I'm using a single handler called ExecutAction(Action action) so I'm catching exceptions in one place rather than repeating in every method.
At the moment, I'm not logging errors. Just alert the user for an action and try to keep the system alive if possible.
When showing messages to users, Presenters will use a static class called MessagingService. (ShowErrorMessage()). So that I can customize all massage boxes in one place.
private void Search()
{
ExecutAction(() =>
{
var info = _DataService.GetByACNo(_model.AccountNumber);
if (info != null)
{
_Model = info ;
this.SetViewPropertiesFromModel(_Model, _View);
}
else
{
MessageBox.Show ("Bank account not found");
}
});
}
private void ExecutAction(Action action)
{
try
{
action();
}
catch (NullReferenceException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlTypes.SqlTypeException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlClient.SqlException e) { MessagingService.ShowErrorMessage(e.Message); }
}
}
Should I include general exception handler to this, to be able to handle any unforeseen exceptions?
Also could you show me a better way to handle showing messages than using a static?
Does use of lambda statements in every method call (ExecutAction(() =>) degrade code readability?
When showing user messages how to show a custom message like "Check the server connection" etc. first and then if the user wants more information (like StackTrace / technical details) he /she could press a button like More Info which is in the MessageBox dialog?
I agree with jeffrey about trying to incorporate IoC for your message service. You could define an abstract base presenter class that has a dependency on an interface for your message service. The base class would be responsible for handling the delegate execution + exception logging.
public interface IMessageService
{
void ShowErrorMessage(Exception e);
}
public abstract class PresenterBase
{
private readonly IMessageService _messageService;
public PresenterBase(IMessageService messageService)
{
this._messageService = messageService;
}
protected void ExecuteAction(Action action)
{
try
{
action();
}
catch (Exception e) { this._messageService.ShowErrorMessage(e); }
}
}
public class SearchPresenter: PresenterBase
{
public SearchPresenter(IMessageService messageService)
: base(messageService)
{
}
public void Search()
{
this.ExecuteAction(() =>
{
//perform search action
});
}
}
Regarding your question about catching all exeptions. Unless you are doing something special for specific types of exceptions, I would suggest just handling all the same. The example I provided passes the exception to the message service so that the formatting specifics can be handled by your message service.
If you have not yet incorporated any sort of IoC container, you can always start by using the interface injection and then passing the instance explicitly from the child class constructor.
public class SearchPresenter: PresenterBase
{
public SearchPresenter()
: base(new SomeMessageService())
{
}
...
}
This is at least removes the static dependency and is not too dificult to swap out later if you ever introduce an IoC container.
I think your approach is good enough for your work. Wrapping logics by ExecuteAction is an acceptable way to me. As another option, I might use AOP for centralized exception handling in practice.
Also, I might use a MessagingService resolved from dependency injection container rather than a static one.
Regarding how to display the error, that's totally depend on your business purpose. For example, you could simply log the error and tell the user "something's wrong", or show them the complete stacktrace including the environment information so they could simply copy & paste in the email.
I use IErrorHandler in my project for handle exceptions.
But how can i log incoming method parameter with exception.
I want to get Request parameter for logging.
Sample Method:
public Response GetData(Request request) {
return new Response();
}
You could get the request message like this:
Message requestMessage = OperationContext.Current.RequestContext.RequestMessage;
What I do usually is to log the entire request XML.
You don't have such information in IErrorHandler - you can only parse raw message in ProvideFault method.
You can try to use another approach - implement custom IOperationInvoker and in Invoke method do something like:
// Just synchronous implementation - for asynchronous handle InvokeBegin and InvokeEnd
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
try
{
// Run common invoker - you will create new Invoker as decorator for existing one.
return innerInvoker.Invoke(instance, inputs, outputs);
}
catch(Exception e)
{
// Handle error here
}
}
Operation invoker is responsible for selection correct operation in service and ivoke it. It is just idea - I haven't tested it.
Two ways:
The native WCF logger will capture all requests & responses when set to verbose however, these files tend to get real big, real quick.
Use log4net (search google to download)
private static readonly ILog log = LogManager.GetLogger(typeof(MyClass));
public class MyClass
{
...
public Foo DoSomething(string arg)
{
try
{
//do something
}
catch(Exception e)
{
log.error(string.format("{0} Arguements: {1}", e.Tostring(), arg);
}
}
}