首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 整合 Enterprise Library Unity 容器實戰

     編輯:關於.NET

核心觀念:依賴注入與物件建立解耦

「依賴抽象而非具體」是鬆耦合設計核心。Unity Application Block 提供輕量、可擴展的 DI 容器,支援建構子注入、屬性注入、方法注入。WCF 服務實例建立預設由 IInstanceProvider 掌控,若將此責任移交 Unity,即可實現服務類別與相依元件的解耦,並享有生命週期管理、攔截等進階功能。

UnityInstanceProvider 實作

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();
    }
}

Behavior 實作:Contract / Endpoint 雙模式

UnityBehaviorAttribute (Contract Behavior)


[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);
    }
    // 其餘介面成員空實作...
}

UnityBehavior / UnityBehaviorElement (Endpoint Behavior)


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);
}

實戰範例:MessageService 多語系訊息服務

Contract


[ServiceContract]
[UnityBehavior(ContainerName = "wcfservice")]
public interface IMessage
{
    [OperationContract] string GetMessage(string key);
}

Service (展示 Unity DI 屬性)


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);
}

Hosting 設定檔 (含 Unity 區段)


<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>

驗證結果

  • Client 呼叫 GetMessage("HelloWorld") 回傳中文訊息,證明:
    1. Unity 解析 IMessageManager 為 MessageManager (屬性注入)。
    2. Initialize() 被自動呼叫設定 Culture (方法注入)。
    3. ResourceManager 正確讀取 zh-CN 資源檔。
  • 移除 [UnityBehavior] 或改用 Endpoint Behavior 設定檔方式,結果一致。

總結

自訂 UnityInstanceProvider 將 WCF 服務實例化完整移交 Unity 容器,支援 Contract/Endpoint 兩種 Behavior 擴展點,配合設定檔靈活註冊型別對應,讓 WCF 服務層輕鬆享有 DI 容器的解耦、生命週期管理、AOP 攔截等企業級能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved