Enterprise Library 為微軟 P&P 開源框架,本系列側重深層實作原理、設計模式、擴展與最佳實踐。首篇探討如何透過自訂 UnityContainerExtension 實現 Unity 與 PIAB 整合。
PIAB 基於 Remoting 方法攔截實現 AOP,需透過 PolicyInjector 建立物件。Unity 建立於 ObjectBuilder 之上,採策略導向物件建立。自訂 BuilderStrategy 在建立前後注入政策:
public class PolicyInjectionStrategy : EnterpriseLibraryBuilderStrategy
{
public override void PreBuildUp(IBuilderContext context)
{
base.PreBuildUp(context);
if (context.Policies.Get<IPolicyInjectionPolicy>(context.BuildKey) == null)
context.Policies.Set<IPolicyInjectionPolicy>(new PolicyInjectionPolicy(true), context.BuildKey);
}
public override void PostBuildUp(IBuilderContext context)
{
base.PostBuildUp(context);
var policy = context.Policies.Get<IPolicyInjectionPolicy>(context.BuildKey);
if (policy != null && policy.ApplyPolicies)
{
policy.SetPolicyConfigurationSource(EnterpriseLibraryBuilderStrategy.GetConfigurationSource(context));
context.Existing = policy.ApplyProxy(context.Existing, BuildKey.GetType(context.OriginalBuildKey));
}
}
}
PreBuildUp 加入 Policy,PostBuildUp 透過 ApplyProxy(內部呼叫 PolicyInjector.Wrap)封裝物件,使 CallHandler 生效。
public class PolicyInjectionExtension : UnityContainerExtension
{
protected override void Initialize()
{
base.Context.Strategies.AddNew<PolicyInjectionStrategy>(UnityBuildStage.Initialization);
}
}
[CachingCallHandler]
public class TimeService : ITimeService
{
public DateTime GetSystemTime() => DateTime.Now;
}
IUnityContainer container = new UnityContainer();
container.AddExtension(new PolicyInjectionExtension());
container.RegisterType<ITimeService, TimeService>();
var instance = container.Resolve<ITimeService>();
for (int i = 0; i < 10; i++)
{
Console.WriteLine(instance.GetSystemTime());
Thread.Sleep(1000);
}
輸出時間相同,證明快取生效。
<unity>
<containers>
<container>
<types>
<type type="Artech.PolicyInjectionIntegratedInUnity.ITimeService, Artech.PolicyInjectionIntegratedInUnity" mapTo="Artech.PolicyInjectionIntegratedInUnity.TimeService, Artech.PolicyInjectionIntegratedInUnity" />
</types>
<extensions>
<add type="Artech.PolicyInjectionIntegratedInUnity.PolicyInjectionExtension, Artech.PolicyInjectionIntegratedInUnity" />
</extensions>
</container>
</containers>
</unity>
程式碼改為讀取配置:
IUnityContainer container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
var instance = container.Resolve<ITimeService>();
// ...
同樣獲得相同輸出。
完整原始碼可供下載參考。