Enterprise Library Policy Injection Application Block (PIAB) 透過方法攔截 實現 AOP,將快取、授權、交易、稽核、例外處理等橫切關注點封裝為 CallHandler,再以 Attribute 或設定檔套用至目標方法。核心在於必須透過 PolicyInjector.Wrap 建立或包裝物件,攔截器才會生效。因此 WCF 整合 PIAB 的關鍵在於:自訂 InstanceProvider,在建立 Service Instance 時經由 PolicyInjector 包裝。
namespace Artech.WCFExtensions
{
public class PolicyInjectionInstanceProvider : IInstanceProvider
{
private readonly Type _serviceContractType;
private readonly string _policyInjectorName;
public PolicyInjectionInstanceProvider(Type serviceContractType, string policyInjectorName)
{
_serviceContractType = serviceContractType;
_policyInjectorName = policyInjectorName;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
PolicyInjector policyInjector = string.IsNullOrEmpty(_policyInjectorName)
? new PolicyInjectorFactory().Create()
: new PolicyInjectorFactory().Create(_policyInjectorName);
Type serviceType = instanceContext.Host.Description.ServiceType;
object serviceInstance = Activator.CreateInstance(serviceType);
// RemotingPolicyInjector 需要目標型別實作介面或繼承 MarshalByRefObject
if (!_serviceContractType.IsInterface && !serviceType.IsMarshalByRef && policyInjector is RemotingPolicyInjector)
return serviceInstance;
return policyInjector.Wrap(serviceInstance, _serviceContractType);
}
public object GetInstance(InstanceContext instanceContext) => GetInstance(instanceContext, null);
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
(instance as IDisposable)?.Dispose();
}
}
}
[AttributeUsage(AttributeTargets.Interface)]
public class PolicyInjectionBehaviorAttribute : Attribute, IContractBehavior
{
public string PolicyInjectorName { get; set; }
public void ApplyDispatchBehavior(ContractDescription contractDescription,
ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = new PolicyInjectionInstanceProvider(
contractDescription.ContractType, PolicyInjectorName);
}
// 其他介面成員略...
}
套用:[PolicyInjectionBehavior] 標註於 Service Contract 介面。
public class PolicyInjectionBehavior : IEndpointBehavior
{
private readonly string _policyInjectorName;
public PolicyInjectionBehavior(string policyInjectorName) => _policyInjectorName = policyInjectorName;
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new PolicyInjectionInstanceProvider(
endpoint.Contract.ContractType, _policyInjectorName);
}
// 其他介面成員略...
}
public class PolicyInjectionBehaviorElement : BehaviorExtensionElement
{
[ConfigurationProperty("policyInjectorName", DefaultValue = "")]
public string PolicyInjectorName { get => (string)this["policyInjectorName"]; set => this["policyInjectorName"] = value; }
public override Type BehaviorType => typeof(PolicyInjectionBehavior);
protected override object CreateBehavior() => new PolicyInjectionBehavior(PolicyInjectorName);
}
設定檔註冊 behaviorExtensions,於 endpointBehaviors 參考。
ITime 含 GetCurrentTime(),標註 [PolicyInjectionBehavior]。TimeService 實作 GetCurrentTime 掛上 [CachingCallHandler],回傳 DateTime.Now。Endpoint Behavior 方式同樣驗證成功,證明兩種擴展途徑皆可行。
透過自訂 IInstanceProvider 結合 PolicyInjector.Wrap,無縫將 PIAB 的 AOP 能力引入 WCF 服務實例化管線,支援 Attribute 與設定檔雙重套用模式,為服務層引入快取、授權、記錄等橫切關注點提供標準化解決方案。