程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Enterprise Library深入解析與靈活應用(1):通過Unity Extension實現和Poli

Enterprise Library深入解析與靈活應用(1):通過Unity Extension實現和Poli

編輯:關於.NET

Enterprise Library深入解析與靈活應用(1):通過Unity Extension實現和Policy Injection Application Block的集成

Enterprise Library是微軟P&P部門開發的眾多Open source框架中的一個,最新的版本已經出到了4.0。由於接觸Enterprise Library 已經有很長的一段時間,在實際的項目中使用的頻率也很高。對此有了一些積累,希望通過這個新的系列和廣大網友一起分享和交流。本系列 假設讀者已經對Enterprise Library有一定的了解,故而不會對各個Application Block的基本原理和編程模型進行介紹,而把側重點放在 Enterprise Library深層次的實現原理、設計模式的應用、有效擴展和最佳實踐上。

今天我們討論的內容是如何通過自定義 UnityContainerExtension實現Unity和PIAB的集成,我們假設讀者已經對Unity Application Block和Policy Injection Application Block已 經有了一定的了解。

1、創建PolicyInjectionStrategy

我們知道Policy Injection Application Block是基於Remoting的原理 通過Method Interception的方式實現了AOP(而另一種常見的方式是基於IL Injection)。要使應用在目標對象的CallHandler發揮作用,需用 通過PolicyInjecctor(默認為Remoting PolicyInjection)進行對象的創建。而實現Unity和PIAB集成的途徑就是讓Unity Container使用進行 對象的創建。

Unity是建立在ObjectBuilder之上的,而ObjectBuilder是整個Enterprise Library以及P&P其他開源框架(比如 Smart Client Software Factory)的基石。ObjectBuilder,顧名思義,就是進行對象創建的組件。而ObjectBuilder進行對象創建的方式是基 於策略的(Strategy based object creation),他通過將不同的策略運用到對象創建(或釋放回收)的不同的階段,而從提供了一個功能強 大的、極具擴展的對象創建的框架。而要實現我們的目標,首先需要創建自定義的BuilderStrategy:PolicyInjectionStrategy 。

namespace Artech.PolicyInjectionIntegratedInUnity
{
  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);
       IPolicyInjectionPolicy 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));
      }
    }
  }
}

上面就是整個PolicyInjectionStrategy 的定義。通過PreBuildUp在對象創建之前將 PolicyInjectionPolicy添加到BuilderContext 的Policy列表中(BuilderContext 為整個對象的創建和生命周期的管理提供context信息)。 在PostBuildUp中,將PolicyInjectionPolicy從BuilderContext 中取出,調用ApplyProxy方法將創建的對象通過PolicyInjecctor進行封裝, 那麼調用被封裝過的對象,我們的Policy Injection CallHandler就可以發揮其作用了。

注:PolicyInjectionPolicy定了在 Microsoft.Practices.EnterpriseLibrary.PolicyInjection dll中,實現了 Microsoft.Practices.EnterpriseLibrary.PolicyInjection.ObjectBuilder.IPolicyInjectionPolicy和 Microsoft.Practices.ObjectBuilder2.IBuilderPolicy。其ApplyProxy方法實際上就是調用了PolicyInjecctor的Wrap方法。

2、創建 PolicyInjectionExtension

有了PolicyInjectionStrategy,我們自定義UnityContainerExtension就顯得很簡單了,需要做的僅僅是 override Initialize方法,創建PolicyInjectionStrategy對象,並將其加入到當前BuilderContext 的Strategie列表中即可。

namespace Artech.PolicyInjectionIntegratedInUnity
{
  public class PolicyInjectionExtension : UnityContainerExtension
  {
    protected override void Initialize()
    {
       base.Context.Strategies.AddNew<PolicyInjectionStrategy>(UnityBuildStage.Initialization);
    }
  }
}

3、通過coding的方式應用PolicyInjectionExtension

我們現在將我們定義的PolicyInjectionExtension使用到實 際的場景中,看看它能夠像我們希望的那樣,調用通過Unity container創建的對象上的方法,其對應的Policy Injection CallHandler能夠被 正常地執行。我們仍然使用CachingCallHandler和TimeService來做試驗。為此,我定義了一個interface(ITimeService) 和他的實現 (TimeService ),並通過cusotom attribute的方式在class上應用了CachingCallHandler。

public interface ITimeService
{
    DateTime GetSystemTime();
}

[CachingCallHandler]
public class TimeService : ITimeService
{
  #region IContract Members

  public DateTime GetSystemTime()
   {
      return DateTime.Now;
  }

    #endregion
  }
}

在Console application的Main()中,先創建UnityContainer對象,然後通過AddExtension將我們定義的PolicyInjectionExtension添加到該 UnityContainer種,然後進行interface和concrete type匹配關系的注冊。最後通過Resolve方法創建ITimeService 對象,並在for循環中以一 定的時間間隔(1s)調用GetSystemTime方法。

namespace Artech.PolicyInjectionIntegratedInUnity
{
  class Program
  {
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.AddExtension(new PolicyInjectionExtension());
            container.RegisterType<ITimeService, TimeService>();
        ITimeService instance = container.Resolve<ITimeService>();
        for (int i = 0; i < 10; i++)
        {
           Console.WriteLine(instance.GetSystemTime());
          Thread.Sleep(1000);
         }
      }    
  } 
}

因為我們在TimeService 使用了CachingCallHandler, GetSystemTime方法返回的結果將會被緩存。所以輸出的時間都是相同的,如下圖所示:

4、通過configuration的方式應用 PolicyInjectionExtension

Unity的主要的目的是實現了DI(dependency injection). DI的目的說白了還是實現松耦合。而送耦合實 現的一個主要的途徑還是將編譯時的依賴轉換成運行時的依賴。所以在很多情況下只用通過配置的方式才能真正意義上實現解耦。而Unity的大 多數使用場景還是基於configuration方式的。為了實現上一節中通過coding一樣的功能,我們定義了如下的Unity配置:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
   <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections> 
   <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>
</configuration>

我們通過配置的方式實現了type的注冊和extension的添加。有了上面的配置, 我們的code進行相應的改動使用unity的配置:

namespace Artech.PolicyInjectionIntegratedInUnity
{
  class Program
  {
    static void Main(string[] args)
    {
      IUnityContainer container = new UnityContainer();
      UnityConfigurationSection unityConfigSection = ConfigurationManager.GetSection ("unity") as UnityConfigurationSection;
      unityConfigSection.Containers.Default.Configure (container);
      ITimeService instance = container.Resolve<ITimeService>();
      for (int i = 0; i < 10; i++)
      {
        Console.WriteLine(instance.GetSystemTime());
         Thread.Sleep(1000);
      }
    }
  }
}

運行上面的代碼,我們一樣可以得到相同的輸 出:

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved