Question

I need to log a lot of stuff all across my domain, hence most of my domain and application services rely on a logging implementation. Let's say I created this small contract:

public interface ILogger {

    void Info(string message);

}

Great. Now I implemented an infrastructure service based on log4net:

public class Log4NetProxy : ILogger {

    private ILog _logger = LogManager.GetLogger();

    public void Info(string message) {
        _logger.Info(message);
    }
}

However, since most of my classes have other dependencies than just a logger, I'm getting closer and closer to a constructor-over-injection pattern..

public class MyService : IMyService {

    public MyService(ILogger logger, IRepository repo, IAlsoNeedSettings settings) {

    }

}

How can I avoid injection of such fundamental core requirements like settings or logging and just focus on the dependencies I really need? Property injection? Service Facades? Static log factory?

Was it helpful?

Solution

[Rant+code about interceptors deleted because that's not what you need :)]

I find that property injection is usually the way to go because it avoids boilerplate code that is usually not really interesting

... and i assign the umpteenth ISomething from the constructor value to the property ...

I don't know how to use it in Autofac (I use mainly Castle.Windsor) but i'd recommend it as a low-maintenance and a good way to avoid constructor bloat

EDIT: Apparently the questions Mark Seemann refer to mention interception as a valid way of handling these cases so i'll put back my original rant + code. I'm not sure it matches what he refers to but it may give you some ideas


I really like the Castle-Windsor interception system which is a bit like Aspect Oriented Programming and where you wrap your resolved components in interceptors which can then decide how to act depending on parameters, method name, etc

here is an example of my interception logger:

public class LoggingInterceptor: IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (Tracer t = new Tracer(string.Format("{0}.{1}", invocation.TargetType.Name, invocation.Method.Name)))
        {
            StringBuilder sb = new StringBuilder(100);
            sb.AppendFormat("IN (", invocation.TargetType.Name, invocation.Method.Name);
            sb.Append(string.Join(", ", invocation.Arguments.Select(a => a == null ? "null" : DumpObject(a)).ToArray()));
            sb.Append(")");
            t.Verbose(sb.ToString());

            invocation.Proceed();

            sb = new StringBuilder(100);
            sb.AppendFormat("OUT {0}", invocation.ReturnValue != null ? DumpObject(invocation.ReturnValue) : "void");
            t.Verbose(sb.ToString());
        }
    }

    private string DumpObject(object argument)
    {
        // serialize object
    }
}

This logger interceptor is then registered during setup and applied to interesting classes in a WCF service:

// register interceptors
_container.Register(
    Classes.FromAssemblyInThisApplication()
    .BasedOn<IInterceptor>()
    .WithServiceBase()
    .Configure(c => c.Named(c.Implementation.Name))
);

// apply them
_container.Register
(
    Component.For<IService>()
        .ImplementedBy<ServicesImplementation.Service>()
        .Named("Service")
        .LifestylePerWcfOperation()
        .Interceptors("LoggingInterceptor")
);

You could consider intercepting calls to a method needing a ILogger or a class with a ILogger property and injecting it from the interceptor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top