问题
I'm trying to add logging with aspect orientated programming using castle windsor in plain asp.net, i.e. not MVC
I've added a class that implements the IInterceptor interface and an attribute that inherits from Attribute.
public class LogAttribute : Attribute
{
public Level LogLevel { get; set; }
public LogAttribute(Level level)
{
LogLevel = level;
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
MethodInfo mi = invocation.Method;
LogAttribute[] atts = (LogAttribute[])mi.GetCustomAttributes(typeof(LogAttribute), true);
// if method not marked with InternalUseRestricted attribute, then pass on call
if (atts.Length == 0)
{
invocation.Proceed();
}
else
{
ISeiLogger log = LoggerFactory.GetLogger(mi.DeclaringType.ToString());
//assume only one logging attribute
//log on entry
log.LogEnter(atts[0].LogLevel);
//allow code to continue
invocation.Proceed();
//log on exit
log.LogExit(atts[0].LogLevel);
}
}
}
Now in the global.asax.cs I've added the following:
public partial class Global : System.Web.HttpApplication, IoCProvider
{
private void InitializeIoC()
{
container = new WindsorContainer();
container.Install(new Sei.Aspect.AspectInstaller());
}
public IWindsorContainer Container
{
get { return container; }
}
private static Sei.Logging.ISeiLogger log;
private IWindsorContainer container;
public override void Init()
{
base.Init();
InitializeIoC();
}
and I've created an installer class:
public class AspectInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IInterceptor>().Configure(component => component.LifeStyle.PerWebRequest));
container.Register(Component.For<IInterceptor>().ImplementedBy<LoggingInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<InternalUseRestrictedInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<CachingInterceptor>().LifeStyle.PerWebRequest);
}
}
I now want to add the attribute to some arbitary page's code behind class and some arbitary virtual method, as in
[Log(Level.Info)]
protected string Login(string username, string password)
{
DoSomething();
}
This obviously doesn't work. Do I need to change the way I'm instantiating the page (its a page's code-behind class) to use a container? Or is it the way I'm registering the interceptors? I want to be able to use the interceptors on any class going forward and not have to tell the container about each and every class that I have in my application.
回答1:
Short answer: it's not possible.
Long answer: due to the way ASP.NET Web Forms works, it doesn't let anyone interfere with the page instantiation. Some claim that using a custom PageHandlerFactory lets you do IoC, but this only lets you set properties after the page has been instantiated, which is simply not enough for proxying.
So runtime proxy libraries such as DynamicProxy or LinFu can't do anything about this. But you may be able to use compile-time aspect weavers, such as PostSharp.
Alternatively, make your code-behind as slim as possible, deferring actual logic to Windsor-managed components.
来源:https://stackoverflow.com/questions/4783287/using-castle-windsor-with-interceptors-and-asp-net