共用方式為


使用 Unity 容器建立自訂解析程式

您可以使用 Unity 應用程式區塊 (Unity) (https://go.microsoft.com/fwlink/?LinkId=188286) 建立自訂解析程式,以插入解析邏輯和中繼資料來源的執行時間相依性。

事實提供者

事實提供者是實作 IFactProvider 介面的類別實例。 這個介面會公開名為 RegisterFact之方法的三個不同多載。 此方法會接受訊息、解析程式組態,在某些情況下,管線內容會傳回 物件。 此物件可能是以某種方式從輸入中擷取的資訊,可能是某種形式的計算,或是從某些外部來源查閱。 事實提供者傳回的每個物件都可以稱為事實,而且通常會由解析容器新增至清單,以供事實翻譯工具稍後使用。

Unity 解析程式可能具有零或多個事實提供者,可以隨時新增或移除單一組態變更。

下列程式碼是事實提供者中包含的邏輯範例。 此程式碼也可以在 ESB 的 ItineraryStaticFactProvider.cs 檔案中找到。Resolver.Itinerary.Facts 專案。 它是 ITINERARY-STATIC 解析程式中的元件,可從解析程式連接字串收集路線的名稱和版本。

public object RegisterFact(IBaseMessage message, IPipelineContext pipelineContext, Dictionary\<string, string\> resolverContents)
{
    return GetItineraryFactFromResolver(resolverContents);
}

private static object GetItineraryFactFromResolver(Dictionary\<string, string\> resolverContents)
{
    if (resolverContents == null)
        throw new ArgumentNullException("resolverContents");

    ItineraryFact itineraryFact = new ItineraryFact();
    itineraryFact.Name = ResolverMgr.GetConfigValue(resolverContents, true, "name");
    string version = ResolverMgr.GetConfigValue(resolverContents, false, "version");
    if (!string.IsNullOrEmpty(version))
    {
        EventLogger.Write(string.Format("Version set with value {0}.", version));
        itineraryFact.SetVersion(version);
    }
    return itineraryFact;
}

事實翻譯工具

事實翻譯工具是實作 IFactTranslator 介面的類別實例。 此介面會公開名為 TranslateFact的單一方法。 這個方法會採用物件陣列,其中包含事實清單,以及解析程式字典,稍後會使用事實翻譯工具傳回解析程式。 事實翻譯工具負責以有意義的方式處理事實提供者所提供的事實,然後填入解析程式字典。

Unity 解析程式可能具有零或多個事實翻譯工具,隨時都可以使用單一設定變更來新增或移除。

下列程式碼是事實翻譯工具中包含的邏輯範例。 此程式碼也可以在 ESB 的 ItineraryStaticFactTranslator.cs 檔案中找到。Resolver.Itinerary.Facts 專案。 它是 ITINERARY-STATIC 解析程式中的元件,它會執行資料庫查詢,依名稱收集路線的行程 XML,並選擇性地依版本收集行程 XML。

public void TranslateFact(object[] facts, Dictionary\<string, string\> factDictionary)
{
    #region Argument Check
    if (null == facts) throw new ArgumentNullException("fact");
    if (null == factDictionary) throw new ArgumentNullException("factDictionary");
    #endregion

    #region Local Variables
    Version version = new Version(1, 0);
    #endregion
    try
    {
        foreach (object fact in facts)
        {
            if (fact is ItineraryFact)
            {
                ItineraryFact targetFact = (ItineraryFact)fact;
                factDictionary.Add(_FactKeyItineraryName, targetFact.Name ?? string.Empty);
                if (null != targetFact.Version)
                {
                    factDictionary.Add(_FactKeyItineraryVersion, targetFact.Version.ToString(2) ?? string.Empty);
                    version = targetFact.Version;
                }

                string xml = null;

                if (targetFact.Version != null)
                {
                    xml = _repositoryProvider.GetItinerary(targetFact.Name, version.Major, version.Minor);
                }
                else
                {
                    xml = _repositoryProvider.GetItinerary(targetFact.Name);
                }
                if (!string.IsNullOrEmpty(xml))
                {
                    factDictionary.Add(_FactKeyItinerary, xml);
                }

                break;
            }
        }
    }
    #region Exception Handling
    catch (System.Exception)
    {
        throw;
    }
    #endregion
}
#endregion

解析容器

解析容器是實作 IResolveContainer 介面的類別。 一般而言,它也會實作 IResolveProvider 介面。 IResolveContainer介面會公開名為Initialize的單一方法,該方法會採用IUnityContainer。 傳遞給這個方法的容器將包含所有相依性 (,也就是 IFactProviderIFactTranslator類別的實例,以及解析程式完成處理所需的任何其他類型) 。

下列程式碼是 IResolveContainer 介面實作的範例。 此程式碼也可以在 ESB 的 StaticItineraryResolveContainer.cs 檔案中找到。Resolver.Itinerary 專案。

#region IResolveContainer Members

private static IUnityContainer Container;

// <summary>
// This is used by the Unity resolver to initialize the current
// object with the Unity container.
// </summary>
// <param name="container">Unity container used for dependency
// injection.</param>
// <remarks>
// The container used is the ITINERARY container, although this is
// configurable in Esb.config.
// </remarks>

public void Initialize(IUnityContainer container)
{
  if (container == null)
    throw new ArgumentNullException("container");

  Container = container;
}
#endregion

在解析容器中,在IResolveProvider介面的Resolve方法實作中,必須逐一查看 Unity 容器中的所有事實提供者和事實翻譯工具,以允許它們執行其處理。

下列程式碼是解析容器中包含的邏輯範例。 此程式碼也可以在 ESB 的 StaticItineraryResolveContainer.cs 檔案中找到。Resolver.Itinerary 專案。

public Dictionary\<string, string\> Resolve(ResolverInfo resolverInfo,
    XLANGMessage message)
{
    #region Argument Check
    if (String.IsNullOrEmpty(resolverInfo.Config))
        throw new ArgumentNullException("resolverInfo.Config");
    if (String.IsNullOrEmpty(resolverInfo.Resolver))
        throw new ArgumentNullException("resolverInfo.Resolver");
    if (null == message)
        throw new ArgumentNullException("message");
    #endregion Argument Check

    return ResolveStatic(resolverInfo.Config, resolverInfo.Resolver,
        (factProvider, resolverContent) =>
            factProvider.RegisterFact(message, resolverContent)
     );
}

private Dictionary\<string, string\> ResolveStatic(string config, string resolver,
    Func<IFactProvider, Dictionary\<string, string\>, object> RegisterFact)
{
    try
    {
        EventLogger.Write(string.Format("Received {0} value in ITINERARY STATIC resolver.", config));

        Dictionary\<string, string\> queryParams =
                ResolverMgr.GetFacts(config, resolver);

        List<object> facts = new List<object>();

        foreach (IFactProvider factProvider in Container.ResolveAll<IFactProvider>())
        {
            facts.Add(RegisterFact(factProvider, queryParams));
        }

        Dictionary\<string, string\> resolverDictionary = new Dictionary\<string, string\>();

        object[] convertedFacts = facts.ToArray();

        foreach (IFactTranslator translator in Container.ResolveAll<IFactTranslator>())
        {
            translator.TranslateFact(convertedFacts, resolverDictionary);
        }

        return resolverDictionary;
    }
    catch (System.Exception ex)
    {
        EventLogger.Write(MethodInfo.GetCurrentMethod(), ex);
        throw;
    }
}

設定自訂 Unity 解析程式

若要設定自訂 Unity 解析程式,建立自訂解析程式時會套用相同的設定步驟;不過,必須包含一些額外的組態,才能正確註冊組成解析程式的元件。

首先,在 Esb.config 檔案的解析程式宣告下,必須新增 resolverConfig 節點,並具有下列兩個屬性:

  • unitySectionName。 此屬性包含組態檔中組態區段的名稱,其中包含 Unity 應用程式區塊的組態;根據預設,此屬性的值是 esb.resolver

  • unityContainerName。 此屬性包含自訂解析程式專屬的 Unity 組態中所定義的 Unity 容器名稱。

    下列 XML 是 解析程式 節點中必要設定的範例。

<resolver name="ITINERARY-STATIC" type="Microsoft.Practices.ESB.Resolver.Unity.ResolveProvider, Microsoft.Practices.ESB.Resolver.Unity, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22">
     <resolverConfig>
          <add name="unitySectionName" value="esb.resolver" />
          <add name="unityContainerName" value="ITINERARY" />
     </resolverConfig>
</resolver>

下列 XML 是 esb.resolver 節點下所需設定的範例。

<typeAliases>
     <!-- Lifetime manager types -->
     <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
     <!-- std type providers -->
     <typeAlias alias="string" type="System.String, mscorlib"/>
     <typeAlias alias="int" type="System.Int32, mscorlib"/>
     <!-- repository providers -->
     <typeAlias alias="IRepositoryProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.Repository.IRepositoryProvider, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="SqlRepositoryProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess.SqlRepositoryProvider, Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <!-- fact providers -->
     <typeAlias alias="IFactProvider" type="Microsoft.Practices.ESB.Resolver.Facts.IFactProvider, Microsoft.Practices.ESB.Resolver.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="IFactTranslator" type="Microsoft.Practices.ESB.Resolver.Facts.IFactTranslator, Microsoft.Practices.ESB.Resolver.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ItineraryFactProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.ItineraryFactProvider, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ItineraryStaticFactProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.ItineraryStaticFactProvider, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ItineraryHeaderFactProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.ItineraryHeaderFactProvider, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ResolutionFactProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.ResolutionFactProvider, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="DefaultFactTranslator" type="Microsoft.Practices.ESB.Resolver.Facts.DefaultFactTranslator, Microsoft.Practices.ESB.Resolver.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ItineraryFactTranslator" type="Microsoft.Practices.ESB.Resolver.Itinerary.Facts.ItineraryFactTranslator, Microsoft.Practices.ESB.Resolver.Itinerary.Facts, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <!-- resolve providers -->
     <typeAlias alias="IResolveProvider" type="Microsoft.Practices.ESB.Resolver.IResolveProvider, Microsoft.Practices.ESB.Resolver, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22"/>
     <typeAlias alias="ItineraryResolveProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.BREItineraryResolverContainer,Microsoft.Practices.ESB.Resolver.Itinerary, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22 "/>
     <typeAlias alias="StaticItineraryResolveProvider" type="Microsoft.Practices.ESB.Resolver.Itinerary.StaticItineraryResolveContainer,Microsoft.Practices.ESB.Resolver.Itinerary, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c62dd63c784d6e22 "/>
</typeAliases>
<containers>
     <container name="ITINERARY">
          <types>
               <type type="IResolveProvider" mapTo="StaticItineraryResolveProvider" />
               <type type="IRepositoryProvider" mapTo="SqlRepositoryProvider" name="CurrentRepositoryProvider">
                    <lifetime type="singleton" />
                    <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
                         <constructor>
                              <param name="connectionStringName" parameterType="string">
                                   <value value="ItineraryDb"/>
                              </param>
                              <param name="cacheManagerName" parameterType="string">
                                   <value value="Itinerary Cache Manager"/>
                              </param>
                              <param name="cacheTimeout" parameterType="string">
                                   <value value="120" />
                              </param>
                         </constructor>
                    </typeConfig>
               </type>
               <type type="IFactProvider" mapTo="ResolutionFactProvider" name="ResolutionFactProvider"  />
               <type type="IFactProvider" mapTo="ItineraryHeaderFactProvider" name="HeaderFactProvider"  />
               <type type="IFactProvider" mapTo="ItineraryStaticFactProvider" name="StaticFactProvider"  />
               <type type="IFactTranslator" mapTo="DefaultFactTranslator" name="DefaultFactTranslator">
                    <lifetime type="singleton" />
               </type>
               <type type="IFactTranslator" mapTo="ItineraryFactTranslator" name="ItineraryFactTranslator">
                    <lifetime type="singleton" />
                    <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
                         <constructor>
                              <param name="repositoryProvider" parameterType="IRepositoryProvider">
                                   <dependency name="CurrentRepositoryProvider"/>
                              </param>
                         </constructor>
                    </typeConfig>
               </type>
          </types>
     </container>
</containers>

如需 esb.resolvers 節點中必要組態的詳細資訊,請參閱 MSDN 上 Unity 應用程式區塊 () https://go.microsoft.com/fwlink/?LinkId=188288 的來源架構。

建立自訂 Unity 解析程式

建立自訂 Unity 解析程式

  1. (選擇性) 使用實作 IFactProvider 介面的類別建立元件或元件,並包含 RegisterFact 方法,提供解析發生所需的資訊。

  2. (選擇性) 使用實作 IFactTranslator 介面的類別建立元件或元件,並包含 TranslateFact 方法,可將提供的事實轉譯為解析程式字典中的索引鍵/值組。

  3. 使用實作 IResolveContainerIResolveProvider 介面的類別來建立元件,其中包含可驗證解析程式組態的 Resolve 方法、從事實提供者收集所有事實、執行任何特製化處理、使用事實翻譯工具翻譯這些事實,並將翻譯的事實當做 Dictionary 類別的實例傳回。

  4. 使用< 包含根 Moniker 做為 name 屬性的解析 >程式,並將完整元件名稱新增至 Esb.config 組態檔,以註冊解析程式。

  5. 將 Unity 特定的組態新增至此解析程式的 Esb.config 檔案。

  6. (選擇性) 建立定義根 Moniker 和查詢參數的架構,然後將它儲存在 ESB 中。Schemas.Resolvers 資料夾。 名稱應遵循現有的 ESB 命名慣例;這表示它應該使用附加 「_Resolution.xsd」 的根 Moniker 名稱。

  7. (選擇性) 從新的架構產生類別,並將它儲存在自訂解析程式元件中。 這會公開自訂解析程式中的具型別參數。

  8. 在全域組件快取中註冊所有元件。