Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / biztalk

BizTalk ESB Toolkit 2.1 – Custom Itinerary Resolver

5.00/5 (1 vote)
16 Oct 2013CPOL2 min read 11.9K  
BizTalk ESB Toolkit 2.1 – Custom Itinerary Resolver

ESB Toolkit 2.1 comes with a pack of resolvers like BRE, UDDI etc. But still a requirement of custom resolver is very common. How to create a custom resolver is well explained on msdn (see Creating a Custom Resolver [http://msdn.microsoft.com/en-us/library/ee236671(v=bts.10).aspx]).

In my recent project I had one custom resolver which I used to use for resolving MAP, End Point and some custom properties. Then I decided to use single resolver across the project for all resolution which also includes itinerary resolution. My first assumption was that resolving itinerary would be straight simple as resolving any other values. Well, I was wrong!!! 

To my surprise there was no key for itinerary in Microsoft.Practices.ESB.Resolver.ResolverKeys and then I also noticed that Toolkit has separate resolvers for itinerary. So what is special in out-of-box ITINERARY resolver and how it works? Below are the simple steps to create your own Itinerary resolver. And how I got this is not a magic.

Add Custom Resolver Config in esb.config

<resolver name="MYRES" type="ResolverService.MyPResolver.ResolveProvider, ResolverService.MyResolver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b9e26ef0f5b76891">
<resolverConfig>
<add name="connectionStringName" value="ItineraryDb"/>
<add name="cacheTimeout" value="120"/>
<add name="cacheManagerName" value="Itinerary Cache Manager"/>
</resolverConfig>
</resolver>

You can see how this configuration is being used in custom resolver provider class constructor in below step,

Add a parameterized constructor in your custom resolver

using Microsoft.Practices.ESB.Resolver.Itinerary.Facts;
using Microsoft.Practices.ESB.Resolver.Facts;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts.Repository;
using Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess;
public class ResolveProvider : IResolveProvider
{
private List<IFactTranslator> _FactTranslators;
public ResolveProvider()
{

}

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

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

……

Implement Resolve Method

There are three overloads available in IResolverProvider, I choose the one which is called from pipeline because I had to resolve itineraries in receive pipeline.

public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
{
if (string.IsNullOrEmpty(config))
{
throw new ArgumentNullException("Value cannot be null or empty. Param: config");
}

Dictionary<string, string> resolverDictionary = new Dictionary<string, string>();
Resolution resolution = new Resolution();
ResolverMgr.SetContext(resolution, message, pipelineContext);
string strItineraryName = <Put your logic here to resolve Itinerary name>;
string[] facts = strItineraryName.Split(new char[]{‘,’}, StringSplitOptions.RemoveEmptyEntries);
string itiResolverConfig = string.Empty;
if (facts.Length == 1)
{
itiResolverConfig = "MYRES:\\\\name=" + facts[0];
}
else
{
itiResolverConfig = "MYRES:\\\\name=" + facts[0] + ";Version=" + facts[1];
}
Dictionary<string, string> dictionary = this.ResolveStatic(itiResolverConfig, resolver, resolution);

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

return resolverDictionary;
}

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

string str = ResolverMgr.GetConfigValue(facts, false, "version");
if (!string.IsNullOrEmpty(str))
{
fact.SetVersion(str);
}

object[] objArray = new object[] { resolution, fact, facts };
foreach (IFactTranslator translator in this._FactTranslators)
{
translator.TranslateFact(objArray, nvps);
}
return nvps;
}

In nutshell, ESB Selector pipeline component just not expects Itinerary Name but also expects complete itinerary XML in resolver dictionary. You can also use your own Data Access component to retrieve Itinerary XML from ItineraryDB database.

Build your custom resolver solution and deploy the DLL in GAC. Your resolver is ready to use in ESB Itinerary Selector. Below screen shot shows how I configured ESB Itinerary Selector component with my resolver,

Hope it will help you. Your suggestions and comments are invited to improve this post. Thanks for reading this.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)