Using Castle.Windsor to register an interceptor for a derived class only, not a base class

I am working on updating our project from .Net 2 to .Net4.5, at the same time I click as many links as I can on NuGet and making sure that the versions are current.

I had a problem getting one of the tests to run

Test classes:

public class Person { public static int PersonBaseMethodHitCount { get; set; } public virtual void BaseMethod() { PersonBaseMethodHitCount = PersonBaseMethodHitCount + 1; } public static int PersonSomeMethodToBeOverriddenHitCount { get; set; } public virtual void SomeMethodToBeOverridden() { PersonSomeMethodToBeOverriddenHitCount = PersonSomeMethodToBeOverriddenHitCount + 1; } } public class Employee : Person { public static int EmployeeSomeMethodToBeOverriddenHitCount { get; set; } public override void SomeMethodToBeOverridden() { EmployeeSomeMethodToBeOverriddenHitCount = EmployeeSomeMethodToBeOverriddenHitCount + 1; } public static int EmployeeCannotInterceptHitCount { get; set; } public void CannotIntercept() { EmployeeCannotInterceptHitCount = EmployeeCannotInterceptHitCount + 1; } public virtual void MethodWithParameter( [SuppressMessage("a", "b"), InheritedAttribute, Noninherited]string foo) { } } public class MyInterceptor : IInterceptor { public static int HitCount { get; set; } public void Intercept(IInvocation invocation) { HitCount = HitCount + 1; invocation.Proceed(); } } 

Test (there are no settings for this device):

 var container = new WindsorContainer(); container.Register(Component.For<MyInterceptor>().ImplementedBy<MyInterceptor>()); container.Register( Component .For<Employee>() .ImplementedBy<Employee>() .Interceptors(InterceptorReference.ForType<MyInterceptor>()) .SelectedWith(new DerivedClassMethodsInterceptorSelector()).Anywhere); container.Register(Classes.FromAssembly(Assembly.GetExecutingAssembly()).Pick().WithService.FirstInterface()); var employee = container.Resolve<Employee>(); Person.PersonBaseMethodHitCount = 0; Person.PersonSomeMethodToBeOverriddenHitCount = 0; Employee.EmployeeCannotInterceptHitCount = 0; Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0; MyInterceptor.HitCount = 0; employee.BaseMethod(); Assert.That(Person.PersonBaseMethodHitCount, Is.EqualTo(1)); // The BaseMethod was not overridden in the derived class so the interceptor should not have been called. Assert.That(MyInterceptor.HitCount, Is.EqualTo(0)); Person.PersonBaseMethodHitCount = 0; Person.PersonSomeMethodToBeOverriddenHitCount = 0; Employee.EmployeeCannotInterceptHitCount = 0; Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0; MyInterceptor.HitCount = 0; employee.SomeMethodToBeOverridden(); Assert.That(Person.PersonSomeMethodToBeOverriddenHitCount, Is.EqualTo(0)); Assert.That(Employee.EmployeeSomeMethodToBeOverriddenHitCount, Is.EqualTo(1)); Assert.That(MyInterceptor.HitCount, Is.EqualTo(1)); //The test errors out on this line Person.PersonBaseMethodHitCount = 0; Person.PersonSomeMethodToBeOverriddenHitCount = 0; Employee.EmployeeCannotInterceptHitCount = 0; Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0; MyInterceptor.HitCount = 0; employee.CannotIntercept(); Assert.That(Employee.EmployeeCannotInterceptHitCount, Is.EqualTo(1)); Assert.That(MyInterceptor.HitCount, Is.EqualTo(0)); 

I added a comment to indicate where the test fails.

As far as I can tell, the problem occurs in DerivedClassMethodsInterceptorSelector

Selection:

 public class DerivedClassMethodsInterceptorSelector : IInterceptorSelector { public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors) { return method.DeclaringType != type ? new IInterceptor[0] : interceptors; } } 

When it does type comparisons, the type variable is System.RuntimeType, but should be Employee (at least that's my understanding).

EDIT: This problem occurred when using Castle.Windsor and Castle.Core 3.2.1. After NuGet has installed the 3.1.0 package, the code works as expected.

I am inclined to think that this is a mistake, but I could just change the logic.

+6
source share
1 answer

I was able to reproduce the same issue with version 3.3.3 with this simple unit test:

 [TestClass] public class MyUnitTest { [TestMethod] public void BasicCase() { var ProxyFactory = new ProxyGenerator(); var aopFilters = new IInterceptor[] {new TracingInterceptor()}; var ConcreteType = typeof(MyChild); var options = new ProxyGenerationOptions { Selector = new AopSelector() }; var proxy = ProxyFactory.CreateClassProxy(ConcreteType, options, aopFilters) as MyChild; proxy.DoIt(); } } public class AopSelector : IInterceptorSelector { public IInterceptor[] SelectInterceptors(Type runtimeType, MethodInfo method, IInterceptor[] interceptors) { Assert.IsTrue(runtimeType == typeof(MyChild)); return interceptors; } } public class MyWay { public virtual void DoIt() { Thread.Sleep(200); } } public class MyChild : MyWay { public virtual void DoIt2() { Thread.Sleep(200); } } public class TracingInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { var isProperty = invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_"); if (isProperty) { invocation.Proceed(); return; } LogMethod(invocation); } protected virtual void LogMethod(IInvocation invocation) { var target = (invocation.InvocationTarget ?? invocation.Proxy).GetType().Name; var stopwatch = Stopwatch.StartNew(); try { stopwatch.Start(); invocation.Proceed(); } finally { stopwatch.Stop(); var result = stopwatch.ElapsedMilliseconds; } } } 

I fixed this by changing the lock source code and the TypeUtil.GetTypeOrNull editing method to look like this:

 public static Type GetTypeOrNull(object target) { if (target == null) { return null; } var type = target as Type; if (type != null) { return type; } return target.GetType(); } 

Of course, this is a naive fix, because the problem is somewhere else, and instead of an instance of the object passed to this method, its Type is passed. However, checking if the passed parameter is of type Type , and if it returns it instead of calling GetType , it makes it work.

+2
source

Source: https://habr.com/ru/post/954623/


All Articles