I wrote a class library for logging and diagnostics. The interface is pretty basic. You call these static methods to log something:
interface ILogger {
void Critical (string message);
void Error (string message);
void Warning (string message);
void Info (string message);
void Verbose (string message);
}
However, I want to append a call context (let's say trace identifier) implicitly to the each message and I want that context to be set/reset by callers of the library (specifically top level caller) rather than pushing trace context down to each method call. Assuming that context can be updated at runtime, the updated information needs to retraverse all the layers. In fact, the trace context can be extended in the future too. So having context passed around each and every method/constructor initialization is definitely not a good design choice.
Given the fact that library is used in different layers of the code and called by various classes and these callers may fork other multiple threads, I want to be able to implement caller-specific singletons - global data that's only global to that caller.
Let's say the top level class can only set/reset the identifier via some Register (Guid traceId) method and down-the-path the callers just call log methods and do not care about the context. Be aware that the number of layers could be high. Think about the following and consider when the number of layers is tens and maybe hundreds making it really really hard to pass the context and make sure log method calls are aware of any update:
class A {
private B bObj;
void Do() {
bObj.DoSomethingElse();
Logger.Critical("some message from A");
}
}
class B {
private C cObj;
void DoSomethingElse() {
cObj.DoAnotherThing();
Logger.Critical("some message from B");
}
}
class C {
private D dObj;
void DoAnotherThing() {
dObj.DoSomethingElse();
Logger.Critical("some message from C");
}
}
I did a quick research find out ThreadStatic, CallContext and HttpContext in ASP.Net, but I couldn't wrap my head around this without having System.Web in multithread environment. ThreadStatic could be the solution, but my main source of confusion is that a caller may fork new threads and what happens to that existing context from that point on in child threads.
In summary, I am looking for a solution that does not require traversing tramp data to callers of the library (method calls or constructors doesn't matter), and I want to keep log method calls to be aware of any updates to the context data.
NOTE: I am not really sure if caller-specific singletons is right way to put this.
UPDATE: Jon Skeet has an article on this issue.
In such cases, I always prefer to think in terms of decoration. Specifically, you have your interface
interface ILogger {
void Critical (string message);
}
then you have a concrete logger
public class ConcreteLogger : ILogger {
public void Cricital( string message ) {
// log somewhere
}
}
and then you have your decorators that can be composed
public class ContextAwareLogger : ILogger {
private string context;
private ILogger decorated;
public ContextAwareLogger( string context, ILogger decorated ) {
this.context = context;
this.decorated = decorated;
}
public void Critical( string message ) {
this.decorated.Critical( this.context + this.message );
}
}
and last but not least, you have a factory:
public class LoggerFactory {
public ILogger Create( string context ) {
if ( !string.IsNullOrEmpty( context ) )
return new ContextAwareLogger( context, new ConcreteLogger() );
else
return new ConcreteLogger();
}
}
This gives your client a detailed control over what happens, without really changing their interface:
// client code
// no context
var logger = new LoggerFactory().Create( null );
logger.Critical( "a critical issue" );
// with context
var logger2 = new LoggerFactory().Create( "context" );
logger2.Critical( "a critical issue" );
Hope you get the idea. Having a bunch of different decorators and a smart factory with several different ways to parametrize your logger creation, you can still rely on the very same logger interface and you let the additional work be done by specific decorators.
Instead of passing pure data results for example List<Customer> between layers you can create a MessageEnvelope<List<Customer>> class. In this MessageEnvelope class you can then have a property of IContext and also a GUID identifier and additional data that you need for your application.
So you have to refactor your code then of course.
This would also work in N-Tier scenarios.
I would not use singetons!
After some research, I found out Stephen Cleary's article Implicit Async Context ("AsyncLocal"). He provides example of how to maintain an implicit context that can flow into the threads.
In my case, the following solves the tramp data traversal:
interface ILogger {
void Critical (string message);
void Error (string message);
void Warning (string message);
void Info (string message);
void Verbose (string message);
void SetContext(string context);
string GetContext();
}
class Logger : ILogger {
void Critical(string message) {
Debug.WriteLine(string.Format("{0}: {1}", GetContext(), message));
}
void SetContext(string context) {
CallContext.LogicalSetData("myContext", context);
}
string GetContext() {
return (string)CallContext.LogicalGetData("myContext") ?? string.Empty;
}
}
Each log method call retrieves the implicit context using CallContext.
Related
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
}
I have a class instance (Eli) which is used in multiple contexts, and which needs to log messages, independent of (but correctly in each) context:
public class Eli
{
void LogMessage(string msg)
{
///what to do here?
}
public void GrillTheCat()
{
LogMessage("I deed it";)
}
}
public class EliWrapper
{
Eli _eli;
Action<string> _logAction;
public EliWrapper(Eli eli, Action<string> logAction)
{
_eli = eli;
_logAction = logAction;
}
public void GrillTheCat()
{
_eli.GrillTheCat(); //I want LogMessage in Eli to invoke the _logAction of this calling instance
}
}
var eli = new Eli();
var wrapper1 = new EliWrapper(eli, msg => Console.WriteLine(msg));
var wrapper2 = new EliWrapper(eli, msg => File.AppendAllText(msg + "\n"));
I realize I could pass in the logger to the GrillTheCat function, but in my real situation, Eli has >10 functions and I don't want to clutter up all of the function signatures just for the sake of logging.
I also realize I could define a LogAction property on Eli, then have the wrappers assign their _logAction value to that property prior to invoking Eli's function, but again I have many functions and it would be somewhat tedious to wrap each one.
What I'm hoping for is a reflection-based solution where Eli's LogMessage function just steps up a couple layers of the call stack, and accesses the wrapper instance's _logAction directly.
What I'm hoping for is a reflection-based solution where Eli's LogMessage function just steps up a couple layers of the call stack, and accesses the wrapper instance's _logAction directly.
I wasn't able to find any reasonable way to access instances outside the current executing method without you heavily modifying signatures(you stated you didn't want to do).
Although I generally would not recommend what you're trying to do because of the tight coupling and general lack of extensibility and intuitiveness - However, I figured out a solution that almost fits the bill.
It is not possible, at least from what I was able to research, to access instance data from calling members. Which is to say you can't walk back up the stack and access instanced variables or objects all will-nilly, unless you explicitly capture and pass them down the stack as you're - err.. um "stacking"?.
The way we work around this is simply by declaring your _logAction as a static member. That way we don't need to access the instance you have of EliWrapper.
What this doesn't do for you is allow you to have multiple EliWrappers with different _logAction's becuase they're static.
Unfortunately without access to the individual instance(which you can't get from the stack - there's no way for Eli to know what EliWrapper wants to do without at least some of the modifications you explicitly wanted to avoid(In my opinion).
Where do we go from here?
Consider
Consider Modifying Eli so it can be used as a base-class that has different versions that log things differently.
Consider Modifying Eli to implement overrides that accept a Action<string> as a override for it's default logging.
Alternatively, but not recommended
Pass the instance of the caller to Eli so it can access instanced(non-static) members on EliWrapper so you don't need to make _logAction static(this would be a simple modification to the code i have provided to you, but would require changing all of Eli's signatures to accommodate object caller.
Store instances of EliWrapper somewhere you can access without instance, such as a static class, where you can access their instance data using reflection without explicitly passing their instances to Eli
Here's the script to access the static field using the stack
public class Eli
{
private readonly Action<string> DefaultLogger = (s) => Console.WriteLine(s);
void LogMessage(string msg)
{
// get the stack so we can get advanced information about
// who called us (CallerMemberNameAttribute was another alternative, but would incur more complex code)
StackTrace stack = new(false);
// step 2 frames up(or however many to get out of Eli and back to the 'caller'
var caller = stack.GetFrame(2)?.GetMethod()?.DeclaringType;
if (caller != null)
{
// check to see if the type that called GrillTheCat()
// has a static private field with the name '_logAction'
var possibleLoggerInCaller = caller.GetField("_logAction", BindingFlags.Static | BindingFlags.NonPublic);
if (possibleLoggerInCaller != null)
{
// get the static value of that field
var possibleLogger = possibleLoggerInCaller.GetValue(null);
// verify that the type of that logger is infact a Action<string>
// since that's what we use to log
if (possibleLogger is Action<string> logger)
{
// log the msg using the overriden logger instead of the default one
logger.Invoke(msg);
return;
}
}
}
// if we got here there wasn't a _logAction in the call stack at frame 2
// so give up and use our default logger
DefaultLogger.Invoke(msg);
}
public void GrillTheCat()
{
LogMessage("I deed it");
}
}
public class EliWrapper
{
Eli _eli;
private static Action<string> _logAction;
public EliWrapper(Eli eli, Action<string> logAction)
{
_eli = eli;
_logAction = logAction;
}
public void GrillTheCat()
{
_eli.GrillTheCat(); //I want LogMessage in Eli to invoke the _logAction of this calling instance
}
}
For my needs, I've gone with throwing exceptions. This procedurally does what I asked: only notifies the calling instance of the message, and requires no modification of function signatures.
Consider implementing a decorator for Eli that implements logging. Here is a rudimentary example that demonstrates this:
// If you haven't already: define an interface for Eli
public interface IEli
{
// Define all Eli's public members
}
// Let Eli implement IEli
public class Eli : IEli
{
...
}
With the existence of the new IEli interface, you can now implement a decorator:
public class LoggingEli : IEli
{
private readonly IEli decoratee;
private readonly Action<string> logAction;
public LoggingEli(IEli decoratee, Action<string> logAction)
{
this.decoratee = decoratee;
this.logAction = logAction;
}
// Implement all IEli members by calling the log action and forwarding
// the call to the decorated IEli instance:
public object SomeEliMethod(string param1, int param2)
{
this.logAction(nameof(SomeEliMethod) + " called for " + param1);
return this.decoratee.SomeEliMethod(param1, param2);
}
// Same for all other 9 IEli methods.
}
Using the new IEli interface and the LoggingEli decorator, you can now construct the following object graph:
var eli = new Eli();
var consoleEli = new LoggingEli(eli, msg => Console.WriteLine(msg));
var fileEli = new LoggingEli(eli, msg => File.AppendAllText(msg + "\n"));
Decorators have the advantage that you are able to add behavior to a class without having to change the original class. Downside is that it is only possible to add behavior at the start or end of the original method, and the behavior only has access to all the parameters going in and out of the called method. In your case, you can't log halfway the method, and can't log anything information that is kept internal to Eli.
In case you need to log halfway or use information that is internal to Eli, you will need to inject the logger into Eli's constructor.
So I have a few instances where I'd like to be able to do this but essentially I'd like to be able to wrap all calls to a Superclass in a derived type. Right now I'm trying to wrap all calls to base method in an Impersonator but I can see other uses for this as well.
An example being
public void CopyFile(string filePath, string destPath)
{
using(var I = new Impersonator("user", ".", "password"))
{
base.CopyFile(string filePath, string destPath);
}
}
Another convenient use might be
public void CopyFile(string filePath, string destPath)
{
try
{
base.CopyFile(string filePath, string destPath);
} catch(Exception e)
{
Log(e.Message);
}
}
Now I'd like to wrap all base calls similarly. Is there a convenient way to do this or do I have to wrap all of these manually?
I'm looking for something like a "foreach baseMethod in Superclass Do This"
Perhaps finding some way to capture incoming calls to the class and wrapping them as an action?
public void ActionWrapper(Action action)
{
try
{
action.Invoke();
} catch(Exception e)
{
Log(e.Message);
}
}
But how would I catch calls to the class in that way?
Honestly this is just to make the class more maintainable and reduce code bloat. I'm open to these or any other approaches.
First, I want to applaud your instinct to deconstruct code this way. Separating concerns like error handling/logging and security/identity from your business logic can do wonders for maintainability.
What you're describing is known as either decoration or interception. Mark Seemann has a good blog post comparing the two approaches in the context of logging.
Without using external tools (like a DI or AOP framework), I think the ActionWrapper method you proposed is a good start. I modified it to show impersonation rather than logging, since I think impersonation is a more interesting use case:
public void ActionWrapper(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
So the question is: How to apply this method efficiently?
Let's assume your existing class is:
public class FileCopier
{
public void CopyFile(string filePath, string destPath)
{
// Do stuff
}
}
You could, as you suggested, create a derived class to add impersonation:
public class FileCopierWithImpersonation : FileCopier
{
public void CopyFile(string filePath, string destPath)
=> WithImpersonation(base.CopyFile(filePath, destPath));
public void WithImpersonation(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
}
Here, FileCopierWithImpersonation serves as a decorator over FileCopier, implemented via inheritance. The WithImpersonation method serves as an interceptor that can apply an impersonation scope over any method.
That should work well enough, but it forces some compromises in implementation. The base class's methods will all need to be marked as virtual. The child class's constructor might need to pass arguments to the base class. It will be impossible to unit test the child class's logic independently of the base class's logic.
So, you might want to extract an interface (IFileCopier) and apply the decorator using composition rather than inheritance:
public class FileCopierWithImpersonation : IFileCopier
{
private readonly IFileCopier _decoratee;
public FileCopierWithImpersonation(IFileCopier decoratee)
{
// If you don't want to inject the dependency, you could also instantiate
// it here: _decoratee = new FileCopier();
_decoratee = decoratee;
}
public void CopyFile(string filePath, string destPath)
=> WithImpersonation(_decoratee.CopyFile(filePath, destPath));
public void WithImpersonation(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
}
If you're using Visual Studio 2019, there's a refactoring option to "Implement Interface through..." that will automatically implement an interface by calling methods of a dependency of the same type. After that, a simple find/replace should be all that's needed to add the interceptor.
You could also look into code generation tools, like T4 Templates to auto-generate the decorators. Beware, though, that T4 is not supported in .NET Core. It looks to be a legacy technology at this point.
From a good design perspective, I would advise not to do this for 2 reasons:
If catching exception is the sole purpose, then don't do it. Catching and swallowing system exceptions is a bad practice
If you want to do some pre-setup or post-processing on every method of base then may be you should choose composition rather than inheritance here.
However, if you have made up your mind then using an array of delegates can solve your problem.
class Derived : Base
{
private Action[] AllActions;
public Derived()
{
AllActions = new Action[]
{
base.DoSomething1,
base.DoSomething2,
base.DoSomethingMore
};
}
public ActionWrapper(int index)
{
try
{
AllActions[index].Invoke();
} catch(Exception e)
{
Log(e.Message);
}
}
}
For simplicity I have used an array. Use a dictionary to keep a key for each base class method.
I see AOP has been suggested but not expanded upon, so I will attempt to cover it then.
I am assuming you are open to making your base class methods virtual. In this case using a Castle DynamicProxy might give you the flexibility you are after. It will allow you to not only inject code before and after parent method execution, but also change input/output parameters depending on your business requirements.
Here's an artist's impression on what your class might look like should you opt for it:
public class FileCopier
{
public virtual void CopyFile(string filePath, string destPath)
{
// do things here
}
}
public class ImpersonationInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var I = new Impersonator("user", ".", "password"))
{
invocation.Proceed();
}
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch (Exception e)
{
Log(e.Message);
}
}
}
public class CustomProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected() {}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo) {}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
// decide whether you need to intercept your method here
return true;
}
}
void Main()
{
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions(new CustomProxyGenerationHook());
var fileCopierProxy = generator.CreateClassProxy(typeof(FileCopier),
options
new IInterceptor[] { // specify list of interceptors
new ImpersonationInterceptor(),
new LoggingInterceptor()
}
) as FileCopier;
fileCopierProxy.CopyFile("src", "dest");
}
Even if you've got a ton of classes and modifying them all by hand is not feasible, you can still work around it by opting for yet another technique called assembly weaving. Project Fody is a good starting point, and this particular problem is best solved with Virtuosity plugin - it basically rewrites your assembly on build to mark all methods virtual so you don't have to do it yourself.
public static T DecoratorActions<T>(string desc, Func<T> func)
{
return Log(desc, () => ImpersonateAndAct(func));
}
public static void DecoratorActions(string desc, Action action)
{
Log(desc, () => ImpersonateAndAct(action));
}
public string Read(string filepath)
{
return DecoratorActions($"Reading file at '{filepath}'",
() => fileService.Read(filepath));
}
Based on these very helpful answers I've been able to determine that, while I may not be able to automatically wrap all methods of a class. I can at least reduce boilplate code and separate concerns by using the Decorator Pattern instead of the standard inheritance.
As such I have a Log method which calls "Entering {methodName}" and "Exiting {methodName}" as well as try/catching for exceptions which it also logs before throwing.
Additionally an inline way of impersonating for a specific action in the ImpersonateAndAct method.
Both of these return type of T so they wrap calls to my decorated fileService without interfering with the products of those methods.
I marked #Xander as the correct answer as he was the chief inspiration for this approach but I wanted to leave an answer to share what I came up with.
I currently have a class written in C# which does some simple error logging stuff. It's been used quite extensively throughout my project.
class LogError
{
//constructor
public LogError() { }
//public methods
public void saveToTextFile() { }
//other similar methods...
}
But, it doesn't seems a good design of this class, as every time I have to create an instance of LogError class before saveToTextFile() method can be used.
So I am thinking of re-designing this class. Would this be a good case to apply Singleton pattern? What about making it static class instead? Any suggestions? Thanks.
The problem with Singleton is that it's hard to use different logging behaviour. Image you want to introduce a "Send an email instead of write to text file" later. It's basically the same if you have
new LogError().DoSomething();
or
LogError.Instance.DoSomething();
except for performance and/or implementation of the LogError class itself.
If you want to add flexibility, you'd better use Dependency Injection (which makes your code clearer than with the Singleton, in addition) or Dependency Lookup (which is somewhere in between).
I would look at Apache log4net. You don't have to worry about anything. You can configure it to log to multiple targets from your configuration file (or in code). The log message template is fully customizable. You can filter and route different log levels (debug/info/warning/error). It's really not worth reinventing the wheel here.
Yes make it singleton and also thread safe
If you are using , any container ( Autofac, Unity etc) then you can make use of the container.
Singleton can be broken ( By using Reflection so be informed )
one of the implementation would be ( this would not required explicit locking )
public class MySingleton
{
private static readonly MySingleton _singtonInstance = new MySingleton();
private MySingleton()
{
}
public static MySingleton SingtonInstance
{
get { return _singtonInstance; }
}
}
You can use interface as your log system facade, like
interface ILoggerFacade{
void Error(Exception e);
void Warning(Exception e);
....
}
after that you need to make interface implementation
class SimpleLogger:ILoggerFacade{
void Error(Exception e){//logging error};
...
}
and finnaly you need enter point to your logger. I ussually use static class but singleton is variant also.
static class sample:
class StaticLogger{
private ILoggerFacade _logger;
StaticLogger(){
//choose ILoggerFacade implementation
_logger=new SimpleLogger();
}
public static ILoggerFacade Logger{
get{ return _logger;}
}
}
If you will use facade interface you can easy change loggers in your project if it will be need.
There is a solution where you have a logging method that is being called once there are exceptions happen anywhere in your application. All you need to have is a general or common exception handler. Here's how.
On your Program.cs (inside your Main() method before the Application.Run) add this code.
Application.ThreadException += CommonExceptionHandler;
Create CommonExceptionHandler event on your Program.cs file let's say next to Main method.
private static void CommonExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
LogError(t.Exception);
}
Create LogError Method on your Program.cs
public static void LogError(Exception ex)
{
var errMsg = ex.Message;
errMsg += ex.InnerException != null ? ex.InnerException.Message : string.Empty;
//TODO: Do what you want if an error occurs
}
This will catch all exceptions occur in your application. You don't need to worry anymore whether you would call your error log class for every catch block in all of your methods
I chose to expose some new behavior using composition vs. injecting a new object into my consumers code OR making the consumer provide their own implementation of this new behavior. Did I make a bad design decision?
I had new requirements that said that I needed to implement some special behavior in only certain circumstances. I chose to define a new interface, implement the new interface in a concrete class that was solely responsible for carrying out the behavior. Finally, in the concrete class that the consumer has a reference to, I implemented the new interface and delegate down to the class that does the work.
Here are the assumptions that I was working with...
I haven an interface, named IFileManager that allows implementors to manage various types of files
I have a factory that returns a concrete implementation of IFileManager
I have 3 implementations of IFileManager, these are (LocalFileManager, DfsFileManager, CloudFileManager)
I have a new requirements that says that I need to manage permissions for only the files being managed by the CloudFileManager, so the behavior for managing permissions is unique to the CloudFileManager
Here is the test that led me to the code that I wrote...
[TestFixture]
public class UserFilesRepositoryTest
{
public interface ITestDouble : IFileManager, IAclManager { }
[Test]
public void CreateResume_AddsPermission()
{
factory.Stub(it => it.GetManager("cloudManager")).Return(testDouble);
repository.CreateResume();
testDouble.AssertWasCalled(it => it.AddPermission());
}
[SetUp]
public void Setup()
{
testDouble = MockRepository.GenerateStub<ITestDouble>();
factory = MockRepository.GenerateStub<IFileManagerFactory>();
repository = new UserFileRepository(factory);
}
private IFileManagerFactory factory;
private UserFileRepository repository;
private ITestDouble testDouble;
}
Here is the shell of my design (this is just the basic outline not the whole shibang)...
public class UserFileRepository
{
// this is the consumer of my code...
public void CreateResume()
{
var fileManager = factory.GetManager("cloudManager");
fileManager.AddFile();
// some would argue that I should inject a concrete implementation
// of IAclManager into the repository, I am not sure that I agree...
var permissionManager = fileManager as IAclManager;
if (permissionManager != null)
permissionManager.AddPermission();
else
throw new InvalidOperationException();
}
public UserFileRepository(IFileManagerFactory factory)
{
this.factory = factory;
}
private IFileManagerFactory factory;
}
public interface IFileManagerFactory
{
IFileManager GetManager(string managerName);
}
public class FileManagerFactory : IFileManagerFactory
{
public IFileManager GetManager(string managerName)
{
IFileManager fileManager = null;
switch (managerName) {
case "cloudManager":
fileManager = new CloudFileManager();
break;
// other managers would be created here...
}
return fileManager;
}
}
public interface IFileManager
{
void AddFile();
void DeleteFile();
}
public interface IAclManager
{
void AddPermission();
void RemovePermission();
}
/// <summary>
/// this class has "special" behavior
/// </summary>
public class CloudFileManager : IFileManager, IAclManager
{
public void AddFile() {
// implementation elided...
}
public void DeleteFile(){
// implementation elided...
}
public void AddPermission(){
// delegates to the real implementation
aclManager.AddPermission();
}
public void RemovePermission() {
// delegates to the real implementation
aclManager.RemovePermission();
}
public CloudFileManager(){
aclManager = new CloudAclManager();
}
private IAclManager aclManager;
}
public class LocalFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
public class DfsFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
/// <summary>
/// this class exists to manage permissions
/// for files in the cloud...
/// </summary>
public class CloudAclManager : IAclManager
{
public void AddPermission() {
// real implementation elided...
}
public void RemovePermission() {
// real implementation elided...
}
}
Your approach to add your new behavior only saved you an initialization in the grand scheme of things because you to implemented CloudAclManager as separate from CloudFileManager anyways. I disagree with some things with how this integrates with your existing design (which isn't bad)...
What's Wrong With This?
You separated your file managers and made use of IFileManager, but you didn't do the same with IAclManager. While you have a factory to create various file managers, you automatically made CloudAclManager the IAclManager of CloudFileManager. So then, what's the point of having IAclManager?
To make matters worse, you
initialize a new CloudAclManager
inside of CloudFileManager every time you try to get its ACL
manager - you just gave factory
responsibilities to your
CloudFileManager.
You have CloudFileManager implement IAclManager on top of having it as a property. You just moved the rule that permissions are unique to CloudFileManager into your model layer rather than your business rule layer. This also results in supporting the unnecessary
potential of circular referencing between self and property.
Even if you wanted
CloudFileManager to delegate the
permission functionality to
CloudAclManager, why mislead other
classes into thinking that
CloudFileManager handles its own
permission sets? You just made your
model class look like a facade.
Ok, So What Should I Do Instead?
First, you named your class CloudFileManager, and rightly so because its only responsibility is to manage files for a cloud. Now that permission sets must also be managed for a cloud, is it really right for a CloudFileManager to take on these new responsibilities? The answer is no.
This is not to say that you can't have code to manage files and code to manage permissions in the same class. However, it would then make more sense for the class to be named something more general like CloudFileSystemManager as its responsibilities would not be limited to just files or permissions.
Unfortunately, if you rename your class it would have a negative effect on those currently using your class. So how about still using composition, but not changing CloudFileManager?
My suggestion would be to do the following:
1. Keep your IAclManager and create IFileSystemManager
public interface IFileSystemManager {
public IAclManager AclManager { get; }
public IFileManager FileManager { get; }
}
or
public interface IFileSystemManager : IAclManager, IFileManager {
}
2. Create CloudFileSystemManager
public class CloudFileSystemManager : IFileSystemManager {
// implement IFileSystemManager
//
// How each manager is set is up to you (i.e IoC, DI, simple setters,
// constructor parameter, etc.).
//
// Either way you can just delegate to the actual IAclManager/IFileManager
// implementations.
}
Why?
This will allow you to use your new behavior with minimal impact to your current code base / functionality without affecting those who are using your original code. File management and permission management can also coincide (i.e. check permissions before attempting an actual file action). It's also extensible if you need any other permission set manager or any other type of managers for that matter.
EDIT - Including asker's clarification questions
If I create IFileSystemManager : IFileManager, IAclManager, would the repository still use the FileManagerFactory and return an instance of CloudFileSystemManager?
No, a FileManagerFactory should not return a FileSystemManager. Your shell would have to update to use the new interfaces/classes. Perhaps something like the following:
private IAclManagerFactory m_aclMgrFactory;
private IFileManagerFactory m_fileMgrFactory;
public UserFileRepository(IAclManagerFactory aclMgrFactory, IFileManagerFactory fileMgrFactory) {
this.m_aclMgrFactory = aclMgrFactory;
this.m_fileMgrFactory = fileMgrFactory;
}
public void CreateResume() {
// I understand that the determination of "cloudManager"
// is non-trivial, but that part doesn't change. For
// your example, say environment = "cloudManager"
var environment = GetEnvMgr( ... );
var fileManager = m_fileMgrFactory.GetManager(environment);
fileManager.AddFile();
// do permission stuff - see below
}
As for invoking permission stuff to be done, you have a couple options:
// can use another way of determining that a "cloud" environment
// requires permission stuff to be done
if(environment == "cloudManager") {
var permissionManager = m_aclMgrFactory.GetManager(environment);
permissionManager.AddPermission();
}
or
// assumes that if no factory exists for the environment that
// no permission stuff needs to be done
var permissionManager = m_aclMgrFactory.GetManager(environment);
if (permissionManager != null) {
permissionManager.AddPermission();
}
I think that composition is exactly the right means to to this kind of trick. But I think you should keep it more simple (KISS) and just make an IAclManager property in the IFileManager and set it to null by default and set the SecurityManager implementation for the cloud service there.
This has different upsides:
You can check if permissions need to be checked by nullchecking the securityManager property. This way, if there doesn't need to be permissionsManaging done (as with localfile system), you don't have exceptions popping up. Like this:
if (fileManager.permissionsManager != null)
fileManager.permissionsManager.addPermission();
When you then carry out the task (to add or delete a file), you can check again if there's a permissionsManager and if the permission is given, if not throw exception (as you'll want to throw the exception when a permission to do an action is missing, not if a permission is missing in general if you're not going to add or delete files).
You can later on implement more IAclManagers for the other IFileManagers when your customer changes the requirements next time the same way as you would now.
Oh, and then you won't have such a confusing hierarchy when somebody else looks at the code ;-)
In general it looks good, but I do have a few suggestions. It seems that your CreateResume() method implementation demands a IFileManager that is also an IAclManager (or else it throws an exception).
If that is the case, you may want to consider adding an overload to your GetManager() method in which you can specify the interface that you require, and the factory can have the code that throws an exception if it doesn't find the right file manager. To accompolish this you can add another interface that is empty but implements both IAclManager and IFileManager:
public interface IAclFileManager : IFileManager, IAclManager {}
And then add the following method to the factory:
public T GetManager<T>(string name){ /* implementation */}
GetManager will throw an exception if the manager with the name given doesn't implement T (you can also check if it derives from or is of type T also).
All that being said, if AddPermissions doesn't take any parameters (not sure if you just did this for the post), why not just call AddPermissions() from CloudFileManager.AddFile() method and have it completely encapsulated from the user (removing the need for the new IAclManager interface)?
In any event, doesn't seem like a good idea to call AddFile in the CreateResume() method and only then throw the exception (since you now you have now created a file without the correct permissions which could be a security issue and also the consumer got an exception so he may assume that AddFile didn't succeed, as opposed to AddPermission).
Good luck!