Basically, I'm trying to add a logging interceptor for each class that doesn't have a ILogger property or field.
The project I'm working with is build using Monorail 2.1, and the latest Castle Windsor stable release (August 2012, 3.1.0).
Let's say that I have:
[ViewComponentDetails("Followers")]
public class FollowersComponent : ViewComponent
{
private readonly ISession NHibernateSession;
public FollowersComponent(ISession session)
{
NHibernateSession = session;
}
public override void Render()
{
IPrincipal loggedUser = EngineContext.CurrentUser;
if ((loggedUser.Identity.AuthenticationType == "Monorail Type") && (loggedUser.Identity.IsAuthenticated))
{
var user = (PrincipalAdapter<Int64>)Session["User"];
PropertyBag["loggedUser"] = NHibernateSession.Get<User>(user.UserId);
RenderView("Followers");
}
}
}
And I want to add to this class, and any other class which doesn't have logging, the following interceptor:
public class AspectLogger : IInterceptor
{
public AspectLogger(ILoggerFactory loggerFactory)
{
LoggerFactory = loggerFactory;
Loggers = new ThreadSafeDictionary<Type, ILogger>();
}
public ILoggerFactory LoggerFactory { get; private set; }
public ThreadSafeDictionary<Type, ILogger> Loggers { get; private set; }
public void Intercept(IInvocation invocation)
{
if (!Loggers.ContainsKey(invocation.TargetType))
{
Loggers.Add(invocation.TargetType, LoggerFactory.Create(invocation.TargetType));
}
ILogger logger = Loggers[invocation.TargetType];
if (logger.IsDebugEnabled) logger.Debug(invocation.PrettyPrint());
try
{
invocation.Proceed();
}
catch (Exception ex)
{
if (logger.IsErrorEnabled) logger.Error(invocation.PrettyPrint(), ex);
throw;
}
}
}
So, using the docs from Windsor's site, and some other blogposts, I have come up with the following installers and facilities: a Nhibernate Installer/Facility which setups the session factory and session, a Monorail installer which adds the Monorail Windsor Facility and registers all the controllers, view components and filters and finally, a logging Installer which add this facility:
public class ExtendedLoggingFacility : LoggingFacility
{
public ExtendedLoggingFacility()
: base()
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi) :
base(loggingApi)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string configFile) :
base(loggingApi, configFile)
{
}
public ExtendedLoggingFacility(string customLoggerFactory, string configFile) :
base(customLoggerFactory, configFile)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string customLoggerFactory, string configFile) :
base(loggingApi, customLoggerFactory, configFile)
{
}
protected override void Init()
{
base.Init();
Kernel.Register(Component.For<IInterceptor>()
.ImplementedBy<AspectLogger>());
Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (!(handler.ComponentModel.Implementation.GetProperties().Any(prop => prop.PropertyType.GetInterfaces().Contains(typeof(ILogger))) || handler.ComponentModel.Implementation.GetFields().Any(l=>l.FieldType.GetInterfaces().Contains(typeof(ILogger)))))
{
handler.ComponentModel.Interceptors.AddIfNotInCollection(new InterceptorReference(typeof(AspectLogger)));
}
}
}
The only problem? No interceptor gets registered! Atleast, according to this unit test:
[TestFixture]
public class ControllersInstallerTests
{
private IWindsorContainer containerWithControllers;
[SetUp]
public void OnSetup()
{
containerWithControllers = new WindsorContainer()
.Install(FromAssembly.Containing(typeof(UserController)));
}
[Test]
public void All_components_which_dont_have_ILogger_as_a_property_or_field_have_an_AspectLog()
{
var allComponents = GetPublicClassesFromApplicationAssembly(p => !(p.GetProperties().Any(prop => prop.PropertyType.IsAssignableFrom(typeof(ILogger)) || p.GetFields().Any(g => g.FieldType.IsAssignableFrom(typeof(ILogger))))));
var allHandlers = GetAllHandlers(containerWithControllers);
foreach (var comp in allComponents)
{
var handlersForComponent = GetHandlersFor(comp, containerWithControllers);
if (handlersForComponent.Length != 0)
Assert.True(handlersForComponent.All(p => p.ComponentModel.HasInterceptors));
}
}