基本的に、ILoggerプロパティまたはフィールドを持たないクラスごとにロギングインターセプターを追加しようとしています。
私が取り組んでいるプロジェクトは、Monorail 2.1と、最新のCastle Windsor安定版リリース(2012年8月、3.1.0)を使用してビルドされています。
私が持っているとしましょう:
[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");
}
}
}
そして、このクラス、およびロギングを持たない他のクラスに、次のインターセプターを追加したいと思います。
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;
}
}
}
そこで、Windsorのサイトのドキュメントと他のいくつかのブログ投稿を使用して、次のインストーラーとファシリティを考え出しました。セッションファクトリとセッションをセットアップするNhibernateインストーラー/ファシリティ、MonorailWindsorファシリティを追加してすべてを登録するMonorailインストーラーコントローラー、ビューコンポーネント、フィルター、そして最後に、この機能を追加するロギングインストーラー:
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)));
}
}
}
唯一の問題?インターセプターは登録されません!少なくとも、この単体テストによると:
[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));
}
}