ESB Toolkit : Create Custom Itinerary Resolver

The below is a demonstration of a custom Itinerary Resolver.  i.e. instead of using the Itinerary-STATIC or Itinerary-BRE resolver we are developing our own here.  Basically we are creating a component to access a custom itinerary fact store. To get this sample code running create a class library and then add a reference to,

  • Microsoft.BizTalk.Pipeline.dll
  • Microsoft.Practices.ESB.Configuration.dll
  • Microsoft.Practices.ESB.Resolver.dll
  • Microsoft.Practices.ESB.Resolver.Facts.dll
  • Microsoft.Practices.ESB.Resolver.Itinerary.dll
  • Microsoft.Practices.ESB.Itinerary.DataAccess.dll
  • Microsoft.Practices.ESB.Resolver.Itinerary.Facts.dll
  • Microsoft.XLANGs.BaseTypes.dll

Sign, compile, and GAC the class library with the below code.  Note the line where the string variable itineraryName is assigned.  Replace this with a call to your repository or alternate rules engine.

using System;
using System.Xml;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.XLANGs.BaseTypes;
using System.Collections.Generic;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.Practices.ESB.Resolver.Facts;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts;
using Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts.Repository;

namespace ItineraryResolvers
{
    public class SampleItineraryResolver : IResolveProvider
    {
        #region Variables

        private List<IFactTranslator> factTranslatorList;
        private static System.Runtime.Caching.ObjectCache cache;

        #endregion 

        #region Constructors

        public SampleItineraryResolver()
        {
        }

        public SampleItineraryResolver(Microsoft.Practices.ESB.Configuration.Resolver resolverConfig)
        {
            IRepositoryProvider repositoryProvider = new SqlRepositoryProvider(ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "connectionStringName"),
                                                                                    ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "cacheManagerName"), 
                                                                                    ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "cacheTimeout"));

            this.factTranslatorList = new List<IFactTranslator>(2);
            this.factTranslatorList.Add(new DefaultFactTranslator());
            this.factTranslatorList.Add(new ItineraryFactTranslator(repositoryProvider));
        }

        #endregion

        #region Public Methods

        public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
        {
            #region Validation

            if (string.IsNullOrEmpty(config))
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(resolver))
            {
                throw new ArgumentNullException("resolver");
            }
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (pipelineContext == null)
            {
                throw new ArgumentNullException("pipelineContext");
            }

            #endregion

            Dictionary<string, string> resolverDictionary = new Dictionary<string, string>();
            Resolution resolution = new Resolution();

            ResolverMgr.SetContext(resolution, message, pipelineContext);

            string itineraryName = "Itineraries1"; // Replace hardcoded name with read on repository
            string[] facts = itineraryName.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries);
            string resolverConfig = string.Empty;

            if (facts.Length == 1)
            {
                resolverConfig = "ITINERARY-CUSTOM:\\\\name=" + facts[0];
            }
            else
            {
                resolverConfig = "ITINERARY-CUSTOM:\\\\name=" + facts[0] + ";Version=" + facts[1];
            }

            Dictionary<string, string> dictionary = this.ResolveItinerary(resolverConfig, resolver, resolution);

            resolverDictionary["Resolver.Itinerary"] = dictionary["Resolver.Itinerary"];
            resolverDictionary["Resolver.ItineraryName"] = dictionary["Resolver.ItineraryName"];
            resolverDictionary[ResolverKeys.InterchangeId] = dictionary[ResolverKeys.InterchangeId];

            return resolverDictionary;
        }

        public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
        {
            throw new Exception("Not Implemented.");
        }

        Dictionary<string, string> IResolveProvider.Resolve(string config, string resolver, XmlDocument message)
        {
            throw new Exception("Not Implemented.");
        }

        #endregion

        #region Private Methods

        private Dictionary<string,string> ResolveItinerary(string config, string resolver, Resolution resolution)
        {
            Dictionary<string, string> facts = ResolverMgr.GetFacts(config, resolver);
            ItineraryFact fact = new ItineraryFact{ Name = ResolverMgr.GetConfigValue(facts, true, "name")};
            Dictionary<string, string> result = new Dictionary<string, string>();

            string version = ResolverMgr.GetConfigValue(facts, false, "version");

            if (!string.IsNullOrEmpty(version))
            {
                fact.SetVersion(version);
            }

            object[] objArray = new object[] { resolution, fact, facts };

            foreach (IFactTranslator translator in this.factTranslatorList)
            {
                translator.TranslateFact(objArray, result);
            }
            return result;
        }

        #endregion
    }
}

Register the new Itinerary resolver with ESBT by adding it to the esb.config as per below.

      <resolver name="ITINERARY-CUSTOM" type="ItineraryResolvers.SampleItineraryResolver, ItineraryResolvers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3a8d04cd32444555">
        <resolverConfig>
          <add name="connectionStringName" value="ItineraryDb" />
          <add name="cacheTimeout" value="120" />
          <add name="cacheManagerName" value="Itinerary Cache Manager" />
        </resolverConfig>
      </resolver>

Now configure the Itinerary Selector component to use the ITINERARY-CUSTOM resolver and job done!

Screen Shot 2015-07-23 at 10.52.49 pm

Advertisements
This entry was posted in BizTalk Server. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s