是否可以在应用程序(任何类型,例如控制台,网络,天蓝色网络角色等)中打开或关闭城堡温莎拦截器以避免应用程序重启?
我的场景是使用类似下面的拦截器来记录方法入口并使用参数退出。
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实例失效。
答案 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进行了测试