Castle Windsor在运行时启用或禁用拦截器

时间:2014-09-30 11:06:08

标签: logging castle-windsor aop interceptor application-restart

是否可以在应用程序(任何类型,例如控制台,网络,天蓝色网络角色等)中打开或关闭城堡温莎拦截器以避免应用程序重启?

我的场景是使用类似下面的拦截器来记录方法入口并使用参数退出。

public class ExampleInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Debug.WriteLine(string.Format("Before method: {0}", invocation.Method.Name));
        invocation.Proceed();
        Debug.WriteLine(string.Format("After method: {0}", invocation.Method.Name));
    }
}

我最初的做法是做这样的事情:

public class InterceptorSelector : IModelInterceptorsSelector
{
    public static bool InterceptorOn = false;

    public bool HasInterceptors(ComponentModel model)
    {
        return
            typeof(ExampleInterceptor) != model.Implementation
            && InterceptorOn
            && model.Implementation.Namespace.StartsWith("MvcApplication1");
    }

    public InterceptorReference[] SelectInterceptors(ComponentModel model, InterceptorReference[] interceptors)
    {
        return new[]
        {
            InterceptorReference.ForType<ExampleInterceptor>()
        };
    }
}

但是我发现一旦拦截器处理了一次方法,就必须有一些内部缓存(毫无疑问,这对于性能优势),因为该方法不会再在InterceptorSelector中被击中。

我拥有的主要用例是一个托管在azure中的WebApi,在多个VM实例上每秒提供数百(如果不是1000)个请求。如果需要调试实时环境,我想在其中一个实例上启用详细日志记录,但同时不希望在启用此日志记录时使VM实例失效。

3 个答案:

答案 0 :(得分:1)

运行时切换逻辑可以通过配置开关轻松实现,或者您可以像K.Kozmic那样进行,如他的动态代理here教程中所示。

答案 1 :(得分:0)

您可以创建一个静态事件,您将拦截拦截器,然后通过操纵控制器类来禁用拦截器

public class ChangeInterceptorSettingsEventArgs : EventArgs {}

public class MyInterceptorsController
{
    public delegate void ChangeInterceptorSettingsEvent(ChangeInterceptorSettingsEventArgs args);
    public static event ChangeInterceptorSettingsEvent ChangeInterceptorSettings;

    public void ChangeInterceptorsSettings(ChangeInterceptorSettingsEventArgs args)
    {
        if (ChangeInterceptorSettings != null)
        {
            ChangeInterceptorSettings(args);
        }
    }
}

然后创建拦截器并注册事件处理程序

public class ExampleInterceptor : IInterceptor
{
    public bool WriteThings { get; set; }
    public ExampleInterceptor()
    {
        MyInterceptorsController.ChangeInterceptorSettings += MyInterceptorsController_ChangeInterceptorSettings;
    }

    void MyInterceptorsController_ChangeInterceptorSettings(ChangeInterceptorSettingsEventArgs args)
    {
        WriteThings = !WriteThings; // this is not very smart, 
        // but I don't want to populate the args in this example
    }

    public void Intercept(IInvocation invocation)
    {
        if (WriteThings) {Debug.WriteLine(string.Format("Before method: {0}", invocation.Method.Name));}
        invocation.Proceed();
        if (WriteThings) {Debug.WriteLine(string.Format("After method: {0}", invocation.Method.Name));}
    }
}

最后要使用它,只需从控制器调用事件

MyInterceptorsController.ChangeInterceptorsSettings(new ChangeInterceptorSetingsEventArgs())
// populate the args parameters with what you need

因此,如果你想从已经解析的对象中删除一些拦截器,你总是可以得到包含拦截器的私有字段并在运行时更改它。我并不是真的建议之前确保拦截器的存在对性能造成影响:

resolvedObject
    .GetType()
    .GetField("__interceptors")
    .SetValue(resolvedObject, new IInterceptor[0]);
// or whatever interceptor array you want to set

答案 2 :(得分:0)

您可以在运行时以这种方式排除/添加拦截器:

public class MyController : Controller
{
    public IResolver iResolver {get;set;}
    public IService someService {get;set;}  

    private UsageMethod()
    {
        ExcludeInterceptors(someService, new [] {typeof(Interceptor1),typeof(Interceptor2)};
        AddInterceptor(someService, typeof(Interceptor1), 0};
    }

    private Castle.DynamicProxy.IInterceptor[] getInterceptorsField(object service)
    {
        var field = service.GetType().GetField("__interceptors");
        return field.GetValue(service) as Castle.DynamicProxy.IInterceptor[];
    }

    private void ExcudeInterceptors(object service, params Type[] interceptorTypes2exclude)
    {           
        var newInterceptors = getInterceptorsField(service).Where(x => !interceptorTypes2exclude.Contains(x.GetType())).ToArray();
        field.SetValue(service, newInterceptors);
    }

    private void AddInterceptor(object service, Castle.DynamicProxy.IInterceptor interceptorType2add, int position)
    {           
        var newInterceptors = getInterceptorsField(service).ToList();
        newInterceptors.Insert(position, iResolver.Resolve(interceptorType2add));
        field.SetValue(service, newInterceptors.ToArray());
    }
}
  

P.S。用Castle.Windsor 3.3.0进行了测试