Castle Windsor intercept method call from within the class

后端 未结 5 1787
予麋鹿
予麋鹿 2020-12-17 05:47

We have components registrations in Castle Windsor container like so

void RegisterComponent() {
    var component = Compon         


        
5条回答
  •  萌比男神i
    2020-12-17 06:27

    We use CreateClassProxy method to create the proxy for the service as it was proposed in an answer to the question Castle Dynamic Proxy not intercepting method calls when invoked from within the class. Then we register the obtained proxy as an implementation for the interface. So our custom RegisterComponent method looks like this

    private void RegisterComponent()
        where TInterface : class 
        where TImplementation : class, TInterface
    {
        var proxyType = new ProxyGenerator().CreateClassProxy().GetType();
        Container.Register(Component.For().ImplementedBy(proxyType));
    }
    

    The full component registration is

    Container = new WindsorContainer();
    Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel));
    
    // Interceptor
    Container.Register(Component.For().ImplementedBy().LifestyleTransient());
    
    // Component registrations
    RegisterComponent();
    

    And, of course, all methods you need to intercept should be virtual since inheritance based proxy is used.

    However a drawback of this solution is that you could not use constructor injection when creating a proxy object. Notice that you are creating "dummy" proxy object with new operator only to get a type of the proxy. Therefore you are unable to use constructor injection only when constructing a dummy proxy, but when you resolve your service via container, injection would work just fine. So this drawback is critical only for components with construction logic being more complex than just assigment of dependencies. If you need only dependency assigments you can try to resolve all dependencies from container manually before creating dummy proxy

    private object[] ResolveConstructorParameters()
    {
        return typeof(TType).GetConstructors()
                            .Single(c => c.IsPublic)
                            .GetParameters()
                            .Select(p => _container.Resolve(p.ParameterType))
                            .ToArray();
    }
    

    and then RegisterComponent would become

    private void RegisterComponent()
        where TInterface : class
        where TImplementation : class, TInterface
    {
        var constructorParameters = ResolveConstructorParameters();
        var proxyType = new ProxyGenerator().CreateClassProxy(typeof(TImplementation), constructorParameters).GetType();
        _container.Register(Component.For().ImplementedBy(proxyType));
    }
    

    You can also just fill arguments with null.

提交回复
热议问题