In Java, it is possible to use AspectJ for adding behavior before and after executing a method, using method annotations. Since C# Attributes seem to be very similar, I was wondering whether it would be possible to achieve similar behavior. I was looking in several tutorials and other sources (1, 2, 3), but none of them helped me.
I thought that maybe I could be able to mimic the behavior by inserting the code into Attribute constructor and making it disposable, like this:
[AttributeUsage(AttributeTargets.Method)]
public class MyWritingAttribute : Attribute, IDisposable
{
public MyWritingAttribute()
{
Console.WriteLine("Attribute created");
}
public void Dispose()
{
Console.WriteLine("Attribute disposed");
}
}
However, when using the attribute like this, only Hello world! got displayed in the console:
class Program
{
static void Main(string[] args)
{
SayHelloWorld();
Console.ReadLine();
}
[MyWriting]
private static void SayHelloWorld()
{
Console.WriteLine("Hello World!");
}
}
I was thinking that maybe Console is not reachable in the attribute, but even when replacing it with throw new Exception() expressions, no exception was thrown. How is it possible that StringLengthAttribute from EF works, but my attribute is not even instantiated? And how do I make the attribute run before and after the decorated method?
You need some framework that is able to handle your attribute appropriately. Only because the attribute exists doesn´t mean it will have any affect.
I wrote some easy engine that does that. It will determine if the attribute is present on the passed action and if so get the reflected methods in order to execute them.
class Engine
{
public void Execute(Action action)
{
var attr = action.Method.GetCustomAttributes(typeof(MyAttribute), true).First() as MyAttribute;
var method1 = action.Target.GetType().GetMethod(attr.PreAction);
var method2 = action.Target.GetType().GetMethod(attr.PostAction);
// now first invoke the pre-action method
method1.Invoke(null, null);
// the actual action
action();
// the post-action
method2.Invoke(null, null);
}
}
public class MyAttribute : Attribute
{
public string PreAction;
public string PostAction;
}
Of course you need some null-ckecks, e.g. in the case the methods don´t exist or aren´t static.
Now you have to decorate your action with the attribute:
class MyClass
{
[MyAttribute(PreAction = "Handler1", PostAction = "Handler2")]
public void DoSomething()
{
}
public static void Handler1()
{
Console.WriteLine("Pre");
}
public static void Handler2()
{
Console.WriteLine("Post");
}
}
Finally you can execute that method within our engine:
var engine = new Engine();
var m = new MyClass();
engine.Execute(m.DoSomething);
Just like with Java and AspectJ, you need separate AoP tooling to inject code like this in .NET.
PostSharp is one such tool, probably the best known. I belive they have support for .NET core since version 5.
This can be accomplished using DynamicProxy.
There is an implementation of a memory caching technique with logic that executes before the method being called. That can be extended to check for the existence of an attribute like this
var attribute = Attribute.GetCustomAttribute(invocation.MethodInvocationTarget, typeof(CachedAttribute)) as CachedAttribute;
if (attribute != null)
{
...
}
The code above can be inside the Intercept method in the Interceptor implementation. CachedAttribute would be your attribute.
The question is similar to Run a method before all methods of a class, hence the same answer applies to both.
Use https://github.com/Fody/Fody . The licencing model is based on voluntary contributions making it the better option to PostSharp which is a bit expensive for my taste.
[module: Interceptor]
namespace GenericLogging
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Assembly | AttributeTargets.Module)]
public class InterceptorAttribute : Attribute, IMethodDecorator
{
// instance, method and args can be captured here and stored in attribute instance fields
// for future usage in OnEntry/OnExit/OnException
public void Init(object instance, MethodBase method, object[] args)
{
Console.WriteLine(string.Format("Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length));
}
public void OnEntry()
{
Console.WriteLine("OnEntry");
}
public void OnExit()
{
Console.WriteLine("OnExit");
}
public void OnException(Exception exception)
{
Console.WriteLine(string.Format("OnException: {0}: {1}", exception.GetType(), exception.Message));
}
}
public class Sample
{
[Interceptor]
public void Method(int test)
{
Console.WriteLine("Your Code");
}
}
}
[TestMethod]
public void TestMethod2()
{
Sample t = new Sample();
t.Method(1);
}
We're working on an API for some hardware and I'm trying to write some tests for it in C#. try-catch blocks for repetitive tasks were making my code bloated and repetitive so for getters I was able to wrap like this:
TestGetter(Func<int> method, double expectedVal)
{
int testMe = 0;
try
{
testMe = method();
PassIfTrue(testMe == expectedVal);
}
catch (Exception e)
{
Fail(e.Message);
}
}
So I query the hardware for some known value and compare. I can call with:
TestGetter( () => myAPI.Firmware.Version, 24); //Or whatever.
Which works quite well. But I'm not sure how to do the same with setters. Ie to ensure that the API actually set a value (and doesn't timeout or whatever when I try to set). I'd like to pass the setter to the test method and invoke it in there.
Bonus question: Is there a way to do this with a generic type? There are some custom types defined in the API and I'm not sure of a good way to write these test wrappers for them without writing a new overloaded method for every type. Thanks for any and all help!
You could pass the getter and the setter to the function:
void TestSetter<T>(Func<T> getter, Action<T> setter, T value)
{
try
{
setter(value);
PassIfTrue(EqualityComparer<T>.Default.Equals(getter(), value));
}
catch (Exception e)
{
Fail(e.Message);
}
}
This sets the value, then gets it and compares to the value passed to the setter.
You'd have to call it like:
TestSetter(() => myAPI.Firmware.Version, v => myAPI.Firmware.Version = v, 24);
You can make them generic like Reeds, but you need to use different comparison methods:
public static void TestGetter<T>(Func<T> method, T expectedVal)
{
try
{
T actual = method();
PassIfTrue(expectedVal.Equals(actual));
}
catch (Exception ex)
{
Fail(ex.Message);
}
}
public static void TestSetter<T>(Action setMethod, Func<T> getMethod, T expectedVal)
{
try
{
setMethod();
T actual = getMethod();
PassIfTrue(expectedVal.Equals(actual));
}
catch (Exception ex)
{
Fail(ex.Message);
}
}
You could also pass in a Comparer action to test them if you don't think the Equals method would work for the expected types.
I have built a c# .net 4.0 library.
all of the methods are public and static.
i want to add an aspect using an aspect programming library that does something like this:
try block
1. call method (if method throws exception)
catch block
2. log the exception and massage the exception
it is a dll (class library project)
can you please advice if there is a way to add try/catch routines in one class instead of wrapping around all methods one by one?
Because you had mentioned word static neither ninject nor castle-windsor nor anything else based upon castle-dynamicproxy would help you, because they able to add aspects around regular method. So you have two options:
Handwritten tracing decorator
Add separate handwritten tracing decorator that will add required functionality without altering of existing code
Benefits
Simple and easy to write yourself
Drawbacks
Almost no call context. This is important for tracing, if you like to know what method actually has been called and what parameters had been passed, etc.
New layer of abstraction around existed code. Instead of calling your static methods, you have to call Decorator that will call your static methods inside
Example
// Decorated calls
TraceDecorator.Aspect(() => StaticLogic.SuccessfulCall());
TraceDecorator.Aspect(() => StaticLogic.ExceptionCall());
TraceDecorator.Aspect(() => StaticLogic.SuccessfulCallWithReturn(42));
TraceDecorator.Aspect(() => StaticLogic.ExceptionCallWithReturn(42));
// Decorator itself
public static class TraceDecorator
{
public static T Aspect<T>(Func<T> func)
{
try
{
return func();
}
catch(Exception ex)
{
LogException(ex);
return default(T);
}
}
public static void Aspect(Action func)
{
try
{
func();
}
catch(Exception ex)
{
LogException(ex);
}
}
private static void LogException(Exception ex)
{
Console.WriteLine("Traced by TraceDecorator: {0}", ex);
}
}
Full sample available here
PostSharp
Take a look at Non-Invasive Tracing & Logging with postsharp
Benefits
Broadcast your aspect without altering existing code or adding attributes by yourself, whatever you found suitable
Separation of concerns: tracing/logging are separated from your logic
and alot more …
Drawbacks
Nothing come for free. But there is a free PostSharp edition available with limited functionality
Sometimes integration with other tools because of post-compilation
See NConcern .NET AOP Framework, an open source project.
Example
Your static class
static public class Calculator
{
static public int Add(int a, int b)
{
return a + b;
}
}
Logger
static public class Logger
{
static public void Log(MethodInfo method, object[] arguments, Exception exception)
{
Console.WriteLine("{0}({1}) exception = {2}", method.Name, string.Join(", ", arguments), exception.Message);
}
}
Aspect : log on exception
public class Logging : IAspect
{
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
yield return Advice.Basic.After.Throwing((instance, arguments, exception) =>
{
Logger.Log(method, arguments, exception);
});
}
}
Joinpoint : methods of Calculator
var calculatorMethods = new Func<MethodInfo, bool>(method => method.ReflectedType == typeof(Calculator));
Activate the logging aspect for joinpoint
Aspect.Weave<Logging>(calculatorMethods);
Is there any way to dynamically intercept method calls in a class in C#, equivalent to the Perl AUTOLOAD mechanism?
Case in point, I have a helper class with a 'core' method that writes to the system Event Log and a couple of convenience overloads to simplify the most common uses.
Now, I am seeing an emerging code pattern where I use try ... catch to attempt to write an entry, but ignore any failures that are related to the actual event log handling. For instance when trying to log an application exception when the event log is full, I want the application to crash with the "real" application exception, not the "event log" exception.
I have currently just created a new set of overloads that encapsulates this, but what I would really like to do is have dynamic handling of these methods, i.e. any method call to a method name starting with "Try" calls the respective "real" method, encapsulated in a try .. catch. This is would be so easy in Perl ;-) but can it even be done in C#?
Some code that might simplify the explanation:
public class SomeClass
{
// Core functionality
public static void WriteToLog(string message, EventLogEntryType type)
{
...
}
// Overloaded methods for common uses
public static void WriteToLog(SomeObject obj)
{
WriteToLog(obj.ToString(), EventLogEntryType.Information);
}
public static void WriteToLog(SomeException ex)
{
WriteToLog(ex.Message, EventLogEntryType.Error);
}
// Additional wrappers that ignores errors
// These are what I'd like to handle dynamically instead of manually:
public static void TryWriteToLog(SomeObject obj)
{
try
{
WriteToLog(obj);
}
catch (Exception logException)
{
Console.WriteLine(logException.Message);
}
}
public static void TryWriteToLog(SomeException ex)
{
try
{
WriteToLog(ex);
}
catch (Exception logException)
{
Console.WriteLine(logException.Message);
}
}
}
Oh...
Much to my surprise, I figured it out over a cup of coffee and it actually works. To paraphrase the initial code snippet, here's what I did:
using System;
using System.Dynamic;
using System.Reflection;
public class SomeClass : DynamicObject
{
// Core functionality
public static void WriteToLog(string message, EventLogEntryType type)
{
...
}
// Overloaded methods for common uses
public static void WriteToLog(SomeObject obj)
{
WriteToLog(obj.ToString(), EventLogEntryType.Information);
}
public static void WriteToLog(SomeException ex)
{
WriteToLog(ex.Message, EventLogEntryType.Error);
}
// Redirect all method calls that start with 'Try' to corresponding normal
// methods, but encapsulate the method call in a try ... catch to ignore
// log-related errors
private static dynamic instance = new SomeClass();
public static dynamic Instance { get { return instance; } }
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args,
out object result)
{
if (binder.Name.StartsWith("Try"))
{
try
{
result = this.GetType().InvokeMember(binder.Name.Substring(3),
BindingFlags.InvokeMethod,
null,
this,
args);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
result = null;
}
return true;
}
else
{
return base.TryInvokeMember(binder, args, out result);
}
}
The following methods can now be invoked, and seems to work as intended:
SomeClass.Instance.WriteToLog(SomeObject obj)
SomeClass.Instance.TryWriteToLog(SomeObject obj)
SomeClass.Instance.WriteToLog(SomeException ex)
SomeClass.Instance.TryWriteToLog(SomeException ex)
SomeClass.Instance.WriteToLog(string message, EventLogEntryType type)
SomeClass.Instance.TryWriteToLog(string message, EventLogEntryType type)
Small caveat: The above code is cleaned up for posting on an official forum, it might not work out of the box.
For a given class I would like to have tracing functionality i.e. I would like to log every method call (method signature and actual parameter values) and every method exit (just the method signature).
How do I accomplish this assuming that:
I don't want to use any 3rd party
AOP libraries for C#,
I don't want to add duplicate code to all the methods that I want to trace,
I don't want to change the public API of the class - users of the class should be able to call all the methods in exactly the same way.
To make the question more concrete let's assume there are 3 classes:
public class Caller
{
public static void Call()
{
Traced traced = new Traced();
traced.Method1();
traced.Method2();
}
}
public class Traced
{
public void Method1(String name, Int32 value) { }
public void Method2(Object object) { }
}
public class Logger
{
public static void LogStart(MethodInfo method, Object[] parameterValues);
public static void LogEnd(MethodInfo method);
}
How do I invoke Logger.LogStart and Logger.LogEnd for every call to Method1 and Method2 without modifying the Caller.Call method and without adding the calls explicitly to Traced.Method1 and Traced.Method2?
Edit: What would be the solution if I'm allowed to slightly change the Call method?
C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.
I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.
As I understand it, this is what you want to do:
[Log()]
public void Method1(String name, Int32 value);
and in order to do that you have two main options
Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.
The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.
The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.
The simplest way to achieve that is probably to use PostSharp. It injects code inside your methods based on the attributes that you apply to it. It allows you to do exactly what you want.
Another option is to use the profiling API to inject code inside the method, but that is really hardcore.
You could achieve it with Interception feature of a DI container such as Castle Windsor. Indeed, it is possible to configure the container in such way that every classes that have a method decorated by a specific attribute would be intercepted.
Regarding point #3, OP asked for a solution without AOP framework. I assumed in the following answer that what should be avoided were Aspect, JointPoint, PointCut, etc. According to Interception documentation from CastleWindsor, none of those are required to accomplish what is asked.
Configure generic registration of an Interceptor, based on the presence of an attribute:
public class RequireInterception : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (HasAMethodDecoratedByLoggingAttribute(model.Implementation))
{
model.Interceptors.Add(new InterceptorReference(typeof(ConsoleLoggingInterceptor)));
model.Interceptors.Add(new InterceptorReference(typeof(NLogInterceptor)));
}
}
private bool HasAMethodDecoratedByLoggingAttribute(Type implementation)
{
foreach (var memberInfo in implementation.GetMembers())
{
var attribute = memberInfo.GetCustomAttributes(typeof(LogAttribute)).FirstOrDefault() as LogAttribute;
if (attribute != null)
{
return true;
}
}
return false;
}
}
Add the created IContributeComponentModelConstruction to container
container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
And you can do whatever you want in the interceptor itself
public class ConsoleLoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Writeline("Log before executing");
invocation.Proceed();
Console.Writeline("Log after executing");
}
}
Add the logging attribute to your method to log
public class Traced
{
[Log]
public void Method1(String name, Int32 value) { }
[Log]
public void Method2(Object object) { }
}
Note that some handling of the attribute will be required if only some method of a class needs to be intercepted. By default, all public methods will be intercepted.
If you write a class - call it Tracing - that implements the IDisposable interface, you could wrap all method bodies in a
Using( Tracing tracing = new Tracing() ){ ... method body ...}
In the Tracing class you could the handle the logic of the traces in the constructor/Dispose method, respectively, in the Tracing class to keep track of the entering and exiting of the methods. Such that:
public class Traced
{
public void Method1(String name, Int32 value) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
public void Method2(Object object) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
}
If you want to trace after your methods without limitation (no code adaptation, no AOP Framework, no duplicate code), let me tell you, you need some magic...
Seriously, I resolved it to implement an AOP Framework working at runtime.
You can find here : NConcern .NET AOP Framework
I decided to create this AOP Framework to give a respond to this kind of needs. it is a simple library very lightweight. You can see an example of logger in home page.
If you don't want to use a 3rd party assembly, you can browse the code source (open source) and copy both files Aspect.Directory.cs and Aspect.Directory.Entry.cs to adapted as your wishes. Theses classes allow to replace your methods at runtime. I would just ask you to respect the license.
I hope you will find what you need or to convince you to finally use an AOP Framework.
Take a look at this - Pretty heavy stuff..
http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Essential .net - don box had a chapter on what you need called Interception.
I scraped some of it here (Sorry about the font colors - I had a dark theme back then...)
http://madcoderspeak.blogspot.com/2005/09/essential-interception-using-contexts.html
I have found a different way which may be easier...
Declare a Method InvokeMethod
[WebMethod]
public object InvokeMethod(string methodName, Dictionary<string, object> methodArguments)
{
try
{
string lowerMethodName = '_' + methodName.ToLowerInvariant();
List<object> tempParams = new List<object>();
foreach (MethodInfo methodInfo in serviceMethods.Where(methodInfo => methodInfo.Name.ToLowerInvariant() == lowerMethodName))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != methodArguments.Count()) continue;
else foreach (ParameterInfo parameter in parameters)
{
object argument = null;
if (methodArguments.TryGetValue(parameter.Name, out argument))
{
if (parameter.ParameterType.IsValueType)
{
System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(parameter.ParameterType);
argument = tc.ConvertFrom(argument);
}
tempParams.Insert(parameter.Position, argument);
}
else goto ContinueLoop;
}
foreach (object attribute in methodInfo.GetCustomAttributes(true))
{
if (attribute is YourAttributeClass)
{
RequiresPermissionAttribute attrib = attribute as YourAttributeClass;
YourAttributeClass.YourMethod();//Mine throws an ex
}
}
return methodInfo.Invoke(this, tempParams.ToArray());
ContinueLoop:
continue;
}
return null;
}
catch
{
throw;
}
}
I then define my methods like so
[WebMethod]
public void BroadcastMessage(string Message)
{
//MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
//return;
InvokeMethod("BroadcastMessage", new Dictionary<string, object>() { {"Message", Message} });
}
[RequiresPermission("editUser")]
void _BroadcastMessage(string Message)
{
MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
return;
}
Now I can have the check at run time without the dependency injection...
No gotchas in site :)
Hopefully you will agree that this is less weight then a AOP Framework or deriving from MarshalByRefObject or using remoting or proxy classes.
First you have to modify your class to implement an interface (rather than implementing the MarshalByRefObject).
interface ITraced {
void Method1();
void Method2()
}
class Traced: ITraced { .... }
Next you need a generic wrapper object based on RealProxy to decorate any interface to allow intercepting any call to the decorated object.
class MethodLogInterceptor: RealProxy
{
public MethodLogInterceptor(Type interfaceType, object decorated)
: base(interfaceType)
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase;
Console.WriteLine("Precall " + methodInfo.Name);
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
Console.WriteLine("Postcall " + methodInfo.Name);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
}
Now we are ready to intercept calls to Method1 and Method2 of ITraced
public class Caller
{
public static void Call()
{
ITraced traced = (ITraced)new MethodLogInterceptor(typeof(ITraced), new Traced()).GetTransparentProxy();
traced.Method1();
traced.Method2();
}
}
You can use open source framework CInject on CodePlex. You can write minimal code to create an Injector and get it to intercept any code quickly with CInject. Plus, since this is Open Source you can extend this as well.
Or you can follow the steps mentioned on this article on Intercepting Method Calls using IL and create your own interceptor using Reflection.Emit classes in C#.
I don't know a solution but my approach would be as follows.
Decorate the class (or its methods) with a custom attribute. Somewhere else in the program, let an initialization function reflect all types, read the methods decorated with the attributes and inject some IL code into the method. It might actually be more practical to replace the method by a stub that calls LogStart, the actual method and then LogEnd. Additionally, I don't know if you can change methods using reflection so it might be more practical to replace the whole type.
You could potentially use the GOF Decorator Pattern, and 'decorate' all classes that need tracing.
It's probably only really practical with an IOC container (but as pointer out earlier you may want to consider method interception if you're going to go down the IOC path).
you need to bug Ayende for an answer on how he did it:
http://ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspx
AOP is a must for clean code implementing, however if you want to surround a block in C#, generic methods have relatively easier usage. (with intelli sense and strongly typed code) Certainly, it can NOT be an alternative for AOP.
Although PostSHarp have little buggy issues (i do not feel confident for using at production), it is a good stuff.
Generic wrapper class,
public class Wrapper
{
public static Exception TryCatch(Action actionToWrap, Action<Exception> exceptionHandler = null)
{
Exception retval = null;
try
{
actionToWrap();
}
catch (Exception exception)
{
retval = exception;
if (exceptionHandler != null)
{
exceptionHandler(retval);
}
}
return retval;
}
public static Exception LogOnError(Action actionToWrap, string errorMessage = "", Action<Exception> afterExceptionHandled = null)
{
return Wrapper.TryCatch(actionToWrap, (e) =>
{
if (afterExceptionHandled != null)
{
afterExceptionHandled(e);
}
});
}
}
usage could be like this (with intelli sense of course)
var exception = Wrapper.LogOnError(() =>
{
MessageBox.Show("test");
throw new Exception("test");
}, "Hata");
Maybe it's to late for this answer but here it goes.
What you are looking to achieve is built in MediatR library.
This is my RequestLoggerBehaviour which intercepts all calls to my business layer.
namespace SmartWay.Application.Behaviours
{
public class RequestLoggerBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger _logger;
private readonly IAppSession _appSession;
private readonly ICreateLogGrain _createLogGrain;
public RequestLoggerBehaviour(ILogger<TRequest> logger, IAppSession appSession, IClusterClient clusterClient)
{
_logger = logger;
_appSession = appSession;
_createLogGrain = clusterClient.GetGrain<ICreateLogGrain>(Guid.NewGuid());
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var name = typeof(TRequest).Name;
_logger.LogInformation($"SmartWay request started: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
var response = await next();
_logger.LogInformation($"SmartWay request ended: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
return response;
}
}
}
You can also create performance behaviours to trace methods that take too long to execute for example.
Having clean architecture (MediatR) on your business layer will allow you to keep your code clean while you enforce SOLID principles.
You can see how it works here:
https://youtu.be/5OtUm1BLmG0?t=1
Write your own AOP library.
Use reflection to generate a logging proxy over your instances (not sure if you can do it without changing some part of your existing code).
Rewrite the assembly and inject your logging code (basically the same as 1).
Host the CLR and add logging at this level (i think this is the hardest solution to implement, not sure if you have the required hooks in the CLR though).
The best you can do before C# 6 with 'nameof' released is to use slow StackTrace and linq Expressions.
E.g. for such method
public void MyMethod(int age, string name)
{
log.DebugTrace(() => age, () => name);
//do your stuff
}
Such line may be produces in your log file
Method 'MyMethod' parameters age: 20 name: Mike
Here is the implementation:
//TODO: replace with 'nameof' in C# 6
public static void DebugTrace(this ILog log, params Expression<Func<object>>[] args)
{
#if DEBUG
var method = (new StackTrace()).GetFrame(1).GetMethod();
var parameters = new List<string>();
foreach(var arg in args)
{
MemberExpression memberExpression = null;
if (arg.Body is MemberExpression)
memberExpression = (MemberExpression)arg.Body;
if (arg.Body is UnaryExpression && ((UnaryExpression)arg.Body).Operand is MemberExpression)
memberExpression = (MemberExpression)((UnaryExpression)arg.Body).Operand;
parameters.Add(memberExpression == null ? "NA" : memberExpression.Member.Name + ": " + arg.Compile().DynamicInvoke().ToString());
}
log.Debug(string.Format("Method '{0}' parameters {1}", method.Name, string.Join(" ", parameters)));
#endif
}