使用 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。 傳遞給這個方法的容器將包含所有相依性 (,也就是 IFactProvider 和 IFactTranslator類別的實例,以及解析程式完成處理所需的任何其他類型) 。
下列程式碼是 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 解析程式
(選擇性) 使用實作 IFactProvider 介面的類別建立元件或元件,並包含 RegisterFact 方法,提供解析發生所需的資訊。
(選擇性) 使用實作 IFactTranslator 介面的類別建立元件或元件,並包含 TranslateFact 方法,可將提供的事實轉譯為解析程式字典中的索引鍵/值組。
使用實作 IResolveContainer 和 IResolveProvider 介面的類別來建立元件,其中包含可驗證解析程式組態的 Resolve 方法、從事實提供者收集所有事實、執行任何特製化處理、使用事實翻譯工具翻譯這些事實,並將翻譯的事實當做 Dictionary 類別的實例傳回。
使用< 包含根 Moniker 做為 name 屬性的解析 >程式,並將完整元件名稱新增至 Esb.config 組態檔,以註冊解析程式。
將 Unity 特定的組態新增至此解析程式的 Esb.config 檔案。
(選擇性) 建立定義根 Moniker 和查詢參數的架構,然後將它儲存在 ESB 中。Schemas.Resolvers 資料夾。 名稱應遵循現有的 ESB 命名慣例;這表示它應該使用附加 「_Resolution.xsd」 的根 Moniker 名稱。
(選擇性) 從新的架構產生類別,並將它儲存在自訂解析程式元件中。 這會公開自訂解析程式中的具型別參數。
在全域組件快取中註冊所有元件。