Freigeben über


Erstellen eines benutzerdefinierten Resolvers mit einem Unity-Container

Sie können einen benutzerdefinierten Resolver mithilfe des Unity-Anwendungsblocks (Unity) (https://go.microsoft.com/fwlink/?LinkId=188286) für die Abhängigkeitsinjektion von Auflösungslogik und Metadatenquellen zur Laufzeit erstellen.

Faktenanbieter

Faktenanbieter sind Instanzen von Klassen, die die IFactProvider-Schnittstelle implementieren. Diese Schnittstelle macht drei verschiedene Überladungen einer Methode namens RegisterFact verfügbar. Diese Methode verwendet die Nachricht, die Auflösungskonfiguration und in einigen Fällen den Pipelinekontext und gibt ein Objekt zurück. Dieses Objekt kann in irgendeiner Weise aus den Eingaben extrahiert werden, es kann eine Berechnung irgendeiner Art sein, oder es kann aus einer externen Quelle stammen. Jedes objekt, das von einem Faktenanbieter zurückgegeben wird, kann als Tatsache bezeichnet werden und wird in der Regel durch den Resolve-Container zur späteren Verwendung durch einen Faktenübersetzer zu einer Liste hinzugefügt.

Ein Unity-Resolver verfügt möglicherweise über null oder mehr Faktenanbieter, die jederzeit mit einer einzigen Konfigurationsänderung hinzugefügt oder entfernt werden können.

Der folgende Code ist ein Beispiel für die Logik, die in einem Faktenanbieter enthalten ist. Dieser Code befindet sich auch in der ItineraryStaticFactProvider.cs Datei der ESB. Resolver.Itinerary.Facts Projekt. Es handelt sich um eine Komponente im ITINERARY-STATIC Resolver, die den Namen und die Version einer Reiseroute aus der Verbindungszeichenfolge des Resolvers sammelt.

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

Faktenübersetzer

Faktenübersetzer sind Instanzen von Klassen, die die IFactTranslator-Schnittstelle implementieren. Diese Schnittstelle macht eine einzelne Methode namens TranslateFact verfügbar. Diese Methode verwendet ein Objektarray, das eine Liste von Fakten und das Resolverwörterbuch enthält, das später vom Resolver mithilfe des Faktenübersetzers zurückgegeben wird. Ein Faktenübersetzer ist dafür verantwortlich, die von den Faktenanbietern bereitgestellten Fakten sinnvoll zu verarbeiten und anschließend das Auflösungswörterbuch zu füllen.

Ein Unity-Resolver verfügt möglicherweise über null oder mehr Faktenübersetzer, die jederzeit mit einer einzigen Konfigurationsänderung hinzugefügt oder entfernt werden können.

Der folgende Code ist ein Beispiel für die Logik, die in einem Faktenübersetzer enthalten ist. Dieser Code befindet sich auch in der ItineraryStaticFactTranslator.cs Datei der ESB. Resolver.Itinerary.Facts Projekt. Es handelt sich um eine Komponente im ITINERARY-STATIC Resolver, die eine Datenbankabfrage ausführt, um die Reiserouten-XML für eine Reiseroute anhand des Namens und optional nach Version zu erfassen.

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

Auflösen von Containern

Ein Auflösungscontainer ist eine Klasse, die die IResolveContainer-Schnittstelle implementiert. In der Regel implementiert sie auch die IResolveProvider-Schnittstelle . Die IResolveContainer-Schnittstelle macht eine einzelne Methode namens Initialize verfügbar, die ein IUnityContainer akzeptiert. Der an diese Methode übergebene Container enthält alle Abhängigkeiten (d. h. Instanzen der Klassen IFactProvider und IFactTranslator und alle anderen erforderlichen Typen), die für den Resolver erforderlich sind, um die Verarbeitung abzuschließen.

Der folgende Code ist ein Beispiel für eine Implementierung der IResolveContainer-Schnittstelle . Dieser Code befindet sich auch in der StaticItineraryResolveContainer.cs Datei der ESB. Resolver.Itinerary-Projekt.

#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

In einem Resolve-Container ist es in den Implementierungen der Resolve-Methoden der IResolveProvider-Schnittstelle erforderlich, alle Faktenanbieter und Faktenübersetzer im Unity-Container zu durchlaufen, damit jeder von ihnen seine Verarbeitung ausführen kann.

Der folgende Code ist ein Beispiel für die Logik, die in einem Resolve-Container enthalten ist. Dieser Code befindet sich auch in der StaticItineraryResolveContainer.cs Datei der ESB. Resolver.Itinerary-Projekt.

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

Konfigurieren eines benutzerdefinierten Unity Resolver

Um einen benutzerdefinierten Unity-Resolver zu konfigurieren, gelten dieselben Konfigurationsschritte wie beim Erstellen eines benutzerdefinierten Resolvers; Es gibt jedoch eine zusätzliche Konfiguration, die enthalten sein muss, um die Komponenten, aus denen der Resolver besteht, ordnungsgemäß zu registrieren.

Zunächst muss in der datei Esb.config unter der Resolverdeklaration ein ResolverConfig-Knoten mit den folgenden beiden Eigenschaften hinzugefügt werden:

  • unitySectionName. Diese Eigenschaft enthält den Namen des Konfigurationsabschnitts in der Konfigurationsdatei, die die Konfiguration für den Unity-Anwendungsblock enthält. Standardmäßig ist der Wert für diese Eigenschaft esb.resolver.

  • unityContainerName. Diese Eigenschaft enthält den Namen des Unity-Containers, der in der Unity-Konfiguration für Ihren benutzerdefinierten Resolver definiert ist.

    Der folgende XML-Code ist ein Beispiel für die Konfiguration, die im Resolver-Knoten erforderlich ist.

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

Der folgende XML-Code ist ein Beispiel für die konfiguration, die unter dem Knoten esb.resolver erforderlich ist.

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

Ausführliche Informationen zu der Konfiguration, die im Knoten esb.resolvers erforderlich ist, finden Sie unter Source Schema for the Unity Application Block (https://go.microsoft.com/fwlink/?LinkId=188288) auf MSDN.

Erstellen eines benutzerdefinierten Unity Resolver

So erstellen Sie einen benutzerdefinierten Unity-Resolver

  1. (Optional) Erstellen Sie eine Assembly oder Assemblys mit einer Klasse, die die IFactProvider-Schnittstelle implementiert, und enthält eine RegisterFact-Methode , die Informationen bereitstellt, die für die Auflösung erforderlich sind.

  2. (Optional) Erstellen Sie eine Assembly oder Assemblys mit einer Klasse, die die IFactTranslator-Schnittstelle implementiert, und enthält eine TranslateFact-Methode , die die bereitgestellten Fakten in Schlüssel-Wert-Paare innerhalb des Resolver-Wörterbuchs übersetzt.

  3. Erstellen Sie eine Assembly mit einer Klasse, die die IResolveContainer - und IResolveProvider-Schnittstelle implementiert und eine Resolve-Methode enthält, die die Resolver-Konfiguration überprüft, alle Fakten von den Faktenanbietern sammelt, jede spezialisierte Verarbeitung durchführt, sie mithilfe der Faktenübersetzer übersetzt und die übersetzten Fakten als Instanz der Dictionary-Klasse zurückgibt.

  4. Registrieren Sie den Resolver, indem Sie ihn der konfigurationsdatei Esb.config hinzufügen, indem Sie ein <Resolver-Element> verwenden, das den Stammmoniker als Namensattribute und den vollqualifizierten Assemblynamen als Typattribute enthält.

  5. Fügen Sie die Unity-spezifische Konfiguration zur Esb.config Datei für diesen Resolver hinzu.

  6. (Optional) Erstellen Sie ein Schema, das den Stammmoniker und die Abfrageparameter definiert, und speichern Sie es dann im ESB. Ordner "Schemas.Resolvers". Der Name sollte den bestehenden ESB-Benennungskonventionen entsprechen; dies bedeutet, dass sie den Namen des Stammmonikers verwenden sollte, der mit "_Resolution.xsd" angefügt ist.

  7. (Optional) Generieren Sie eine Klasse aus dem neuen Schema, und speichern Sie sie in der benutzerdefinierten Resolverassembly. Dadurch werden eingegebene Parameter im benutzerdefinierten Resolver verfügbar gemacht.

  8. Registrieren Sie alle Assemblys im globalen Assembly-Cache.