Enterprise Library 中 PIAB(Policy Injection Application Block)定位為輕量級 AOP 框架,Unity 為 IoC 容器。PIAB 透過方法攔截實現策略注入,Unity 則負責依賴注入與物件建立。若能讓 Unity 依照 PIAB 要求建立可攔截物件,即可實現兩者整合。
新版本已提供原生整合:透過 Microsoft.Practices.Unity.InterceptionExtension.Interception 擴展實現。範例定義 ISyncTimeServiceProvision 與 SyncTimeServiceProvisionService,後者依賴 ISyncTimeProvider 介面,由 SyncTimeProvider 實作並標註 [CachingCallHandler]。
IUnityContainer container = new UnityContainer();
container.RegisterType<ISyncTimeServiceProvision, SyncTimeServiceProvisionService>();
container.RegisterType<ISyncTimeProvider, SyncTimeProvider>();
container.AddNewExtension<Interception>();
container.Configure<Interception>().SetDefaultInterceptorFor(typeof(ISyncTimeProvider), new TransparentProxyInterceptor());
var service = container.Resolve<ISyncTimeServiceProvision>();
for (int i = 0; i < 5; i++)
{
Console.WriteLine(service.GetCurrentTime());
Thread.Sleep(1000);
}
輸出時間相同,證明快取處理器生效,整合成功。
原生整合需手動為每個需攔截型別註冊 Interceptor,不具擴展性。解決方案:繼承 InstanceInterceptionStrategy 與 TypeInterceptionStrategy,在 PreBuildUp 動態註冊 Interceptor。
public class ExtendedInterception : Interception
{
public IInterceptor Interceptor { get; internal set; }
public ExtendedInterception() => this.Interceptor = new TransparentProxyInterceptor();
protected override void Initialize()
{
this.Context.Strategies.Add(new ExtendedInstanceInterceptionStrategy(this), UnityBuildStage.Setup);
this.Context.Strategies.Add(new ExtendedTypeInterceptionStrategy(this), UnityBuildStage.PreCreation);
this.Context.Container.RegisterInstance<InjectionPolicy>(typeof(AttributeDrivenPolicy).AssemblyQualifiedName, new AttributeDrivenPolicy());
}
}
兩個策略類別分別處理實例與型別層級攔截,於 PreBuildUp 判斷型別是否可攔截並自動設定預設 Interceptor。
使用時無需手動註冊:
IUnityContainer container = new UnityContainer();
container.RegisterType<ISyncTimeServiceProvision, SyncTimeServiceProvisionService>();
container.RegisterType<ISyncTimeProvider, SyncTimeProvider>();
ExtendedInterception interception = new ExtendedInterception();
interception.Interceptor = new TransparentProxyInterceptor();
container.AddExtension(interception);
var service = container.Resolve<ISyncTimeServiceProvision>();
// ...
定義 ExtendedInterceptionElement 繼承 UnityContainerExtensionConfigurationElement,支援配置指定 Interceptor 型別:
<unity>
<containers>
<container>
<types>
<type type="ISyncTimeServiceProvision" mapTo="SyncTimeServiceProvisionService" />
<type type="ISyncTimeProvider" mapTo="SyncTimeProvider" />
</types>
<extensionConfig>
<add name="extendedInterception" type="Artech.InterceptableUnity.ExtendedInterceptionElement, Artech.InterceptableUnity" interceptor="Microsoft.Practices.Unity.InterceptionExtension.TransparentProxyInterceptor, Microsoft.Practices.Unity.Interception" />
</extensionConfig>
</container>
</containers>
</unity>
程式碼簡化為:
IUnityContainer container = new UnityContainer();
UnityConfigurationSection config = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
config.Containers.Default.Configure(container);
var service = container.Resolve<ISyncTimeServiceProvision>();
// ...
完整原始碼可供下載參考。