Create a Custom Resolver

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The Resolver and Adapter Provider Framework implementation within the ESB Guidance uses a pipeline component named Dispatcher and pipelines named ItineraryReceive and ItinerarySend, all located in the folder Source\Core\Source\ESB.Itinerary.Pipelines.

The Dispatcher pipeline component has four properties: Validate, Enabled, EndPoint, and MapName. The EndPoint property can contain resolver connection strings with values such as the following, where UDDI:\\ represents the resolution type to use (the root moniker).

UDDI:\\serverUrl=https://localhost/uddi;serviceName=OrderPurchaseToOrderPost;serviceProvider=Microsoft.Practices.ESB

Other supported monikers include WSMEX:\\, XPATH:\\, STATIC:\\, and BRE:\\. For example, the following is an example of a WSMEX moniker.

WSMEX:\\serverUrl=https://localhost:9904/wsmex;QName={http://tempuri.org/concurservice}ConcurService

Each of the moniker types uses a specific class that implements the IResolveProvider interface. You can create your own custom resolvers for other moniker types and register them for use by the dynamic resolution system.

The moniker equates to a resolver connection string. Individual schemas, located in the folder \Source\Core\Source\ESB.Resolver.Schemas, define the parameters and their root moniker. A resolver takes the resolver connection string, validates it, and uses the result to query and populate a generic EndPoint property inserted into a Dictionary object that BizTalk can use.

Resolver Configuration

You must register all resolvers in the configuration files BTSNTSvc.exe.config and in Machine.config. The following listing shows an example of the configuration file content.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="ESBProcessor">
      <section name="Resolver"
               type="System.Configuration.DictionarySectionHandler,
                     System,Version=2.0.0.0, Culture=neutral,
                     PublicKeyToken=b77a5c561934e089"/>
      <section name="AdapterProvider"
               type="System.Configuration.DictionarySectionHandler,
                     System,Version=2.0.0.0, Culture=neutral,
                     PublicKeyToken=b77a5c561934e089"/>
      <section name="ItineraryCache"
               type="System.Configuration.DictionarySectionHandler,
                     System,Version=2.0.0.0, Culture=neutral,
                     PublicKeyToken=b77a5c561934e089"/>
      <section name="Cache"
               type="System.Configuration.DictionarySectionHandler,
                     System,Version=2.0.0.0, Culture=neutral,
                     PublicKeyToken=b77a5c561934e089"/>
    </sectionGroup>
  </configSections>
  <ESBProcessor>
    <Resolver>
      <add key="UDDI"
           value="Microsoft.Practices.ESB.Resolver.UDDI,
                  Version=1.0.0.0, Culture=neutral,
                  PublicKeyToken=c2c8b2b87f54180a" />
      <add key="WSMEX"
           value="Microsoft.Practices.ESB.Resolver.WSMEX,
                  Version=1.0.0.0, Culture=neutral,
                  PublicKeyToken=c2c8b2b87f54180a" />
      <add key="XPATH"
           value="Microsoft.Practices.ESB.Resolver.XPATH,
                  Version=1.0.0.0, Culture=neutral,
                  PublicKeyToken=c2c8b2b87f54180a" />
      <add key="STATIC"
           value="Microsoft.Practices.ESB.Resolver.STATIC,
                  Version=1.0.0.0, Culture=neutral,
                  PublicKeyToken=c2c8b2b87f54180a" />
      <add key="BRE"
           value="Microsoft.Practices.ESB.Resolver.BRE,
                  Version=1.0.0.0, Culture=neutral,
                  PublicKeyToken=c2c8b2b87f54180a" />
    </Resolver>
    <AdapterProvider>
      <!— list of adapter providers here -->
    </AdapterProvider>
    <ItineraryCache>
      <add key="timeout" value="120" />
    </ItineraryCache>
    <Cache>
      <add key="UDDI" value="600" />
      <add key="WSMEX" value="600" />
    </Cache>
  </ESBProcessor>
</configuration>

For information about how to edit the BTSNTSvc.exe.config and Machine.config files when installing the ESB Guidance, and the relevant content for each one, see the section "Configure BizTalk and Machine.config Files" in the topic Installing Services and Components.

The schemas for each resolution type, located in the ESB.Resolver.Schemas project, define all the parameters valid for each type of connection string. For example, the following is the schema for the WSMEX Resolver.

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="https://schemas.microsoft.com/BizTalk/2003" 
    xmlns="http://schemas.microsoft.biztalk.practices.esb.com/itinerary" 
    targetNamespace="http://schemas.microsoft.biztalk.practices.esb.com/
    itinerary" xmlns:xs="http://www.w3.org/2001/XMLSchema">  <xs:element name="WSMEX">
    <xs:complexType>
      <xs:attribute name="QName" type="xs:string" />
      <xs:attribute name="serverUrl" type="xs:string" />
      <xs:attribute name="serviceKey" type="xs:string" />
    </xs:complexType>
  </xs:element>
</xs:schema>

Notice in the preceding schema that the root name coincides with the moniker that represents the resolver in both the connection string and in the configuration file, whereas the schema attributes represent the configuration parameters within the configuration string.

The IResolveProvider Interface

All resolvers must implement the IResolveProvider interface. In the source code for the ESB Guidance, all resolver projects are named ESB.Resolver.*, where * is the name of the resolver (such as WSMEX or UDDI).

The IResolveProvider interface, located in the Microsoft.Practices.ESB.Resolver project, consists of three overloads of the Resolve method that return an instance of the Dictionary class, which contains resolution facts provided by the instance of concrete resolver class. The following listing shows the signature of these method overloads.

/// </summary>
/// <param name="config">Configuration string entered into the 
                        pipeline component as argument</param>
/// <param name="resolver">Moniker representing the Resolver to load</param>
/// <param name="message">IBaseMessage passed from the pipeline</param>
/// <param name="pipelineContext">IPipelineContext passed from 
                 the pipeline</param>
/// <returns>Dictionary object fully populated</returns>
Dictionary<string, string> Resolve(string config, string resolver,
                   IBaseMessage message, IPipelineContext pipelineContext);

/// </summary>
/// <param name="config">Configuration string entered into a Web 
                         service as the argument</param>
/// <param name="resolver">Moniker representing the Resolver to load</param>
/// <param name="message">XML document passed from the Web service</param>
/// <returns>Dictionary object fully populated</returns>
Dictionary<string,string> Resolve(string config, string resolver,
                                  System.Xml.XmlDocument message);

/// </summary>
/// <param name="resolverInfo">Configuration string containing the 
                               configuration and resolver</param>
/// <param name="message">XLANGMessage passed from orchestration</param>
/// <returns>Dictionary object fully populated</returns>
Dictionary<string, string> Resolve(ResolverInfo resolverInfo,
                   XLANGs.BaseTypes.XLANGMessage message);

The Resolution structure, located in Microsoft.Practices.ESB.Resolver project also defines the name/value pairs stored in the Dictionary instance. The Resolution structure exposes several properties; the following table lists the most relevant of these. The Dictionary instance supports the addition of custom resolver name/value pairs through a concrete implementation of the Resolver class.

Property

Data type

Property

Data type

TransformType

String

methodNameField

String

Sucess

Boolean

actionField

String

TransportNamespace

String

epmRRCorrelationTokenField

String

TransportType

String

inboundTransportLocationField

String

TransportLocation

String

interchangeIDField

String

Action

String

receiveLocationNameField

String

MessageExchangePattern

String

receivePortNameField

String

EndPointConfig

String

inboundTransportTypeField

String

TargetNamespace

String

isRequestResponseField

String

FixJaxRPC

Boolean

documentSpecStrongNameField

String

SucessEnd

Boolean

documentSpecNameField

String

windowUserField

String

MessageType

String

Creating a Custom Resolver

At run time, a pipeline retrieves the resolver connection string and calls the resolver manager (an instance of the ResolverMgr class located in the \Source\Core\Source\ESB.Resolver folder). The resolver manager parses, populates, and validates the resolver connection string. It does this by doing the following:

  • It parses the connection string to determine which Resolver type to load.
  • It matches this type to a moniker defined in the configuration file (the key is the root moniker, such as UDDI or WSMEX).
  • It reads the assembly name of the resolver for this moniker.
  • It loads the specified assembly.

The dynamic resolution mechanism caches all loaded implementations of the IResolveProvider interface to avoid repeated reading of configuration information and assembly loading when several incoming messages use the same resolver.

Finally, the resolver manager executes the Resolve method of the concrete IResolveProvider implementation and returns the populated Dictionary instance.

To create a custom resolver

  1. Create an assembly that implements the IResolveProvider interface and contains a Resolve method that returns resolver facts as an instance of the Dictionary class.
  2. Register the resolver by adding it to the BTSNTSvc.exe.config and Machine.config configuration files using an <add> element that contains the root moniker as the name attribute and the fully qualified assembly name as the value attribute.
  3. (Optional) Create a schema that defines the root moniker and the query parameters, and then save it in the ESB.Schemas.Resolvers folder. The name should follow existing ESB naming conventions; this means it should use the name of the root moniker appended with "_Resolution.xsd".
  4. (Optional) Generate a class from the new schema and save it in the custom resolver assembly. This will expose typed parameters within the custom resolver.
  5. Register the new assembly in the global assembly cache.