「依賴抽象而非具體」是鬆耦合設計核心。Unity Application Block 提供輕量、可擴展的 DI 容器,支援建構子注入、屬性注入、方法注入。WCF 服務實例建立預設由 IInstanceProvider 掌控,若將此責任移交 Unity,即可實現服務類別與相依元件的解耦,並享有生命週期管理、攔截等進階功能。
namespace Artech.WCFExtensions
{
public class UnityInstanceProvider : IInstanceProvider
{
private readonly Type _contractType;
private readonly string _containerName;
public UnityInstanceProvider(Type contractType, string containerName)
{
_contractType = contractType ?? throw new ArgumentNullException(nameof(contractType));
_containerName = containerName;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
var unitySection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
if (unitySection == null) throw new ConfigurationErrorsException("Missing unity configuration section.");
var container = new UnityContainer();
var containerElement = string.IsNullOrEmpty(_containerName)
? unitySection.Containers.Default
: unitySection.Containers[_containerName];
containerElement.Configure(container);
// 若設定檔未註冊 Contract->Service 對應,自動以 ServiceType 註冊
var typeElements = containerElement.Types.Cast<UnityTypeElement>().ToArray();
if (!typeElements.Any(e => e.Type == _contractType))
container.RegisterType(_contractType, instanceContext.Host.Description.ServiceType);
return container.Resolve(_contractType);
}
public object GetInstance(InstanceContext instanceContext) => GetInstance(instanceContext, null);
public void ReleaseInstance(InstanceContext instanceContext, object instance)
=> (instance as IDisposable)?.Dispose();
}
}
[AttributeUsage(AttributeTargets.Interface)]
public class UnityBehaviorAttribute : Attribute, IContractBehavior
{
public string ContainerName { get; set; }
public void ApplyDispatchBehavior(ContractDescription contractDescription,
ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = new UnityInstanceProvider(
contractDescription.ContractType, ContainerName);
}
// 其餘介面成員空實作...
}
public class UnityBehavior : IEndpointBehavior
{
private readonly string _containerName;
public UnityBehavior(string containerName) => _containerName = containerName;
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(
endpoint.Contract.ContractType, _containerName);
}
// 其餘介面成員空實作...
}
public class UnityBehaviorElement : BehaviorExtensionElement
{
[ConfigurationProperty("containerName", DefaultValue = "")]
public string ContainerName { get => (string)this["containerName"]; set => this["containerName"] = value; }
public override Type BehaviorType => typeof(UnityBehavior);
protected override object CreateBehavior() => new UnityBehavior(ContainerName);
}
[ServiceContract]
[UnityBehavior(ContainerName = "wcfservice")]
public interface IMessage
{
[OperationContract] string GetMessage(string key);
}
public class MessageService : IMessage
{
[Dependency] // 屬性注入
public IMessageManager MessageManager { get; set; }
[InjectionMethod] // 方法注入 (初始化)
public void Initialize()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-CN");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
}
public string GetMessage(string key)
=> MessageManager.GetMessage(key, Thread.CurrentThread.CurrentUICulture);
}
public interface IMessageManager
{
string GetMessage(string key, CultureInfo culture, params object[] parameters);
}
public class MessageManager : IMessageManager
{
public ResourceManager ResourceManager { get; set; }
public MessageManager() => ResourceManager = new ResourceManager("Artech.Messages.Service.Properties.Resources", typeof(Resources).Assembly);
public string GetMessage(string key, CultureInfo culture, params object[] parameters)
=> string.Format(culture, ResourceManager.GetString(key, culture), parameters);
}
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<system.serviceModel> ... </system.serviceModel>
<unity>
<containers>
<container name="wcfservice">
<types>
<type type="Artech.Messages.Service.IMessageManager, Artech.Messages.Service"
mapTo="Artech.Messages.Service.MessageManager, Artech.Messages.Service" />
</types>
</container>
</containers>
</unity>
GetMessage("HelloWorld") 回傳中文訊息,證明:IMessageManager 為 MessageManager (屬性注入)。Initialize() 被自動呼叫設定 Culture (方法注入)。[UnityBehavior] 或改用 Endpoint Behavior 設定檔方式,結果一致。自訂 UnityInstanceProvider 將 WCF 服務實例化完整移交 Unity 容器,支援 Contract/Endpoint 兩種 Behavior 擴展點,配合設定檔靈活註冊型別對應,讓 WCF 服務層輕鬆享有 DI 容器的解耦、生命週期管理、AOP 攔截等企業級能力。