3

我們的組件註冊在溫莎城堡容器,像這樣城堡溫莎攔截方法從類中調用

void RegisterComponent<TInterface, TImplementation>() { 
    var component = Component.For<TInterface>().ImplementedBy<TImplementation>(); 
    component.Interceptors<SomeInterceptor>(); 
    container.Register(component); 
} 

但是我們到了這個問題,當我們做一個方法調用從類中它沒有得到截獲。例如,我們有一個像

ServiceA : IService { 

    public void MethodA1() { 
     // do some stuff 
    } 

    public void MethodA2() { 
     MethodA1(); 
    } 

} 

組件,如果我們所說的一些其他類MethodA2MethodA1方法被截獲,但MethodA2稱爲因爲調用是在類的內部時MethodA1顯然不是攔截。

我們也發現了類似情況下與解決方案Castle Dynamic Proxy not intercepting method calls when invoked from within the class 但是該解決方案使用new運營商,因爲我們使用的容器,它不適合我們的情況下,功能部件和代理的創建。我們可以使用這種解決方案與上面的組件註冊嗎?還是有其他方法可以解決這個問題嗎?

回答

3

截取從MethodA2調用時,你需要使用基於繼承攔截(那是因爲你正在使用this參考,可調用)上MethodA1工作。

爲了使基於繼承攔截可能首先你需要做MethodA1MethodA2virtual

然後你就可以報名容器像這樣:

container.Register(Component.For<ServiceA>().Interceptors<SomeInterceptor>()); 
container.Register(Component.For<IService>().UsingFactoryMethod(c => c.Resolve<ServiceA>())); 

先註冊服務作爲自身應用攔截器(這將增加基於繼承攔截在服務)。然後您可以註冊將使用之前註冊的服務的界面。

+0

有什麼方式來註冊服務作爲接口,但使用基於繼承的攔截沒有這個黑客?爲什麼它默認禁用? – xumix

+0

不幸的是我不知道,它可以讓你改變默認的攔截機制的任何開關,但我從來沒有真的需要這所以從來沒有真正開始認真的。我通常在應用層服務上使用攔截來完成事務管理等事情。所以在我的情況下,它並沒有太大的SENS有這種行爲(例如,如果外攔截方法調用期間已經打開的事務我不希望爲內部方法調用再次發生)。 –

+0

@剋日什托夫·-kozmic所以有使用基於繼承攔截沒有簡單的方法? – xumix

1

我們使用CreateClassProxy方法爲服務創建代理,因爲它是在對問題Castle Dynamic Proxy not intercepting method calls when invoked from within the class的回答中提出的。 然後我們將獲得的代理註冊爲接口的實現。 所以我們的定製RegisterComponent方法看起來像這樣

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

完整的組件註冊爲

Container = new WindsorContainer(); 
Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel)); 

// Interceptor 
Container.Register(Component.For<IInterceptor>().ImplementedBy<SomeInterceptor>().LifestyleTransient()); 

// Component registrations 
RegisterComponent<ISomeService, SomeService>(); 

,當然,你需要攔截所有的方法應該是virtual由於使用了基於繼承的代理。

但是這種解決方案的缺點是在創建代理對象時不能使用構造函數注入。 請注意,您正在使用new運算符創建「虛擬」代理對象,以獲取代理的類型。因此,只有在構建虛擬代理時才能使用構造函數注入,但是當通過容器解析服務時,注入將會很好地工作。所以這個缺點僅對於構建邏輯比僅依賴分配更復雜的組件來說至關重要。如果你只需要依賴assigments你可以嘗試創建虛擬代理

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

之前手動解決從容器中的所有依賴關係,然後RegisterComponent將成爲

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

您也可以只需填寫論點null

+0

你爲什麼不嘗試覆蓋DefaultProxyFactory並在那裏實現基於繼承的代理?無法使用構造函數注入對我來說是一個阻礙:( – xumix

+0

@xumix我已經用更多的解釋更新了我的答案。也許稍後我會嘗試覆蓋'DefaultProxyFactory',但是您也可以嘗試爲此問題添加另一個答案: ) – NikolayKondratyev

2

更改你的註冊到以下和溫莎應該切換到類代理 - 代替組合物即使用繼承截取。

void RegisterComponent<TInterface, TImplementation>() { 
    container.Register(Component.For<TInterface,TImplementation>().ImplementedBy<TImplementation>().Interceptors<SomeInterceptor>()); 
} 
+0

這不是一個解決方案,因爲您無法註冊所有控制器。或者你必須一一註冊。 – xumix

+0

?這是由提問者提供的註冊方法,對強制類代理進行單一更改。 –

1

@NikolayKondratyev我看着https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Windsor/Proxy/DefaultProxyFactory.cs#L110 ,我已經做了登記的簡便方法: container.Register(Classes.FromThisAssembly().BasedOn(typeof(IRepositoryBase<,>)) .WithServiceAllInterfaces().WithServiceSelf() .LifestyleTransient());

注意.WithServiceSelf()通話,這實際上開關類爲主代理

+0

我想這與註冊組件實現類似於其他提議的服務相​​同。 – NikolayKondratyev

+0

@NikolayKondratyev不,這不僅增加了服務的本身,還增加了其所有接口。你也不需要使用這種方法一個接一個地註冊組件 – xumix

+0

我在說'WithServiceSelf'。好的解決方案 – NikolayKondratyev