Castle Windsor intercetta la chiamata al metodo all’interno della class

Abbiamo registrazioni di componenti nel container di Castle Windsor in questo modo

void RegisterComponent() { var component = Component.For().ImplementedBy(); component.Interceptors(); container.Register(component); } 

Tuttavia abbiamo avuto il problema che quando facciamo una chiamata al metodo all’interno della class non viene intercettata. Ad esempio abbiamo componenti simili

 ServiceA : IService { public void MethodA1() { // do some stuff } public void MethodA2() { MethodA1(); } } 

E se chiamiamo metodi MethodA2 o MethodA1 da qualche altra class viene intercettato, ma MethodA1 apparentemente non viene intercettato quando chiamato da MethodA2 poiché la chiamata proviene dalla class.

Abbiamo trovato un caso simile con la soluzione Castle Dynamic Proxy che non ha intercettato le chiamate di metodo quando è stata richiamata dalla class Tuttavia la soluzione presenta la creazione di componenti e proxy utilizzando un new operatore che non è adatto nel nostro caso poiché utilizziamo il contenitore. Possiamo usare questa soluzione con la registrazione dei componenti come sopra? O ci sono altri approcci per risolvere il problema?

Perché l’intercettazione funzioni su MethodA1 quando viene invocato da MethodA2 devi utilizzare l’intercettazione basata sull’ereditarietà (è perché stai utilizzando this riferimento per effettuare l’invocazione).

Per rendere ansible l’intercettazione basata sull’ereditari, è necessario MethodA1 rendere MethodA1 e MethodA2 virtual .

Quindi puoi effettuare la registrazione del contenitore in questo modo:

 container.Register(Component.For().Interceptors()); container.Register(Component.For().UsingFactoryMethod(c => c.Resolve())); 

Prima registra il tuo servizio come se stesse applicando gli interceptor (questo aggiungerà l’intercettazione basata sull’eredità sul servizio). Quindi è ansible registrare l’interfaccia che utilizzerà il servizio registrato in precedenza.

Cambia la tua registrazione a quanto segue e Windsor dovrebbe passare ai proxy di class, ovvero utilizzare l’ereditarietà per l’intercettazione, anziché la composizione.

 void RegisterComponent() { container.Register(Component.For().ImplementedBy().Interceptors()); } 

Usiamo il metodo CreateClassProxy per creare il proxy per il servizio così come è stato proposto in una risposta alla domanda Castle Dynamic Proxy che non intercetta le chiamate al metodo quando viene invocato dall’interno della class . Quindi registriamo il proxy ottenuto come implementazione per l’interfaccia. Quindi il nostro metodo RegisterComponent personalizzato ha questo aspetto

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

La registrazione completa del componente è

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

E, naturalmente, tutti i metodi che devi intercettare dovrebbero essere virtual poiché viene utilizzato il proxy basato sull’ereditarietà.

Tuttavia uno svantaggio di questa soluzione è che non è ansible utilizzare l’iniezione del costruttore durante la creazione di un object proxy. Si noti che si sta creando un object proxy “fittizio” con un new operatore solo per ottenere un tipo di proxy. Pertanto, non è ansible utilizzare l’iniezione del costruttore solo quando si costruisce un proxy fittizio, ma quando si risolve il servizio tramite container, l’iniezione funzionerebbe correttamente. Quindi questo svantaggio è fondamentale solo per i componenti con logica di costruzione più complessa della semplice assegnazione delle dipendenze. Se sono necessari solo assunzioni di dipendenza, è ansible provare a risolvere manualmente tutte le dipendenze dal contenitore prima di creare un proxy fittizio

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

e quindi RegisterComponent diventerebbe

 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)); } 

Puoi anche riempire gli argomenti con null .

@NikolayKondratyev Ho esaminato https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Windsor/Proxy/DefaultProxyFactory.cs#L110 e ho effettuato la registrazione in modo semplice: container.Register(Classes.FromThisAssembly().BasedOn(typeof(IRepositoryBase<,>)) .WithServiceAllInterfaces().WithServiceSelf() .LifestyleTransient());

Nota. .WithServiceSelf() chiamata .WithServiceSelf() , questo .WithServiceSelf() proxy basato sulla class