代码之家  ›  专栏  ›  技术社区  ›  krisg

AOP拦截属性

  •  4
  • krisg  · 技术社区  · 15 年前

    所以,我有这个问题,似乎没人能帮忙。所以我不想一直打下去,我要把它扔出去,换一种方法去剥这只猫的皮。

    我目前有以下:

    public interface ICustomerService
    {
        Customer GetCustomer(int id);
    }
    
    public class CustomerService : ICustomerService
    {
        public Customer GetCustomer(int id)
        {
            ...
        }
    }
    

    …有了Unity,我就有了IOC设置,同时配置拦截功能,比如:

    IUnityContainer ioc = new UnityContainer();
    ioc.RegisterType<ICustomerService, CustomerService>()
        .Configure<Interception>()
        .SetInterceptorFor<ICustomerService>(new InterfaceInterceptor());
    

    我想要实现的是能够像这样在界面中放置属性:

    public interface ICustomerService
    {
        [Log]
        Customer GetCustomer(int id);
    }
    

    …定义如下:

    public class LogAttribute: HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHandler();
        }
    }  
    

    …然后在loghandler类中完成我想要的所有日志记录:

    public class LogHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            ... log stuff
        }
    }
    

    我要实现的是一个跟踪/日志记录系统,其中处理程序记录正在调用的namespace.class.methodname和调用该名称的父namespace.class.methodname。我尝试使用“input”imethodinvocation参数来获取我想要的信息,但没有成功,问题是,input返回“i customerservice”接口,同时检查父级的stackframe返回父级的实现类(例如customerservice),这意味着当我尝试使用namespace.class.methodname作为实体id创建树结构,id和parentid不匹配。

    把一个参数放到[log]属性中也不起作用,因为我能在里面放些什么呢?如果我输入接口名,我仍然会遇到与上面相同的问题,其中一个的id是接口,父类是实现类。而且,我不能将实现类名放在接口的属性中,因为这首先会破坏拥有接口的目的!

    所以,这就是迪勒玛。有人有新主意吗?

    2 回复  |  直到 14 年前
        1
  •  1
  •   user207462    15 年前

    我最终使用postsharp实现了这样的日志记录。 http://www.postsharp.org

        2
  •  1
  •   code4life    14 年前

    我已经开始使用unity和interception进行日志记录。由于我可怕的缺乏配置设置技能,我不得不通过编程来完成。您需要设置至少一个拦截器以及一个或多个策略对象。哦,是的, UnityContainer.Configure<Interception> 是关键。

    有点像这样:

    // I'm using the TransparentProxyInterceptor because I want to trace EVERYTHING...
    var intp = myUnityContainer.Configure<Interception>().
        SetInterceptorFor(typeof(MyTypeToLog), new TransparentProxyInterceptor());
    
    var policy = intp.AddPolicy("somePolicyName");
    
    policy.AddMatchingRule<TypeMatchingRule>(
        new InjectionConstructor(
            new InjectionParameter(typeof(MyTypeToLog)))
              .AddCallHandler(typeof(MyCallHandler), 
                   new ContainerControlledLifetimeManager());
    

    当然,我还需要定义拦截调用处理程序:

    public class MyCallHandler : ICallHandler, IDisposable
    {
        public IMethodReturn Invoke(IMethodInvocation input, 
            GetNextHandlerDelegate getNext)
        {
            var methodReturn = getNext().Invoke(input, getNext);
    
            // log everything...
            LogMethodCall(input, methodReturn);
    
            // log exception if there is one...
            if (methodReturn.Exception != null)
            {
                LogException(methodReturn);
            }
    
            return methodReturn;
        }
    }