ESB Toolkit : Custom Endpoint Resolver

Out of the box we get a stack of nice resolvers. STATIC and UDDI being the most popular. Recently I had a requirement to source my endpoint configuration from a custom SQL database. We have no SQL resolver with ESBT so I needed a custom resolver.

So firstly, what do I mean by “endpoint resolver”. Basically the component that at runtime fetches information that will ultimately be used by ESBT adapter providers to populate context properties used by dynamic send ports when send messages via an Off Ramp.

Let’s look at some code. Basically we need to create a class that implements the IResolverProvider interface. Quick Tip : Reflector is your friend here. Disassembling the UDDI resolver will provide a wealth of information.

– First create a new class library and add a reference to Microsoft.Practices.ESB.Resolver.dll.

– Add the below public methods to satisfy the IResolverProvider Interface

    public class ResolveProvider : IResolveProvider
    {
        #region Public Methods

        Dictionary<string, string> IResolveProvider.Resolve(string config, string resolver, XmlDocument message)
        {
            try
            {
                Dictionary<string, string> dictionary;
                if (string.IsNullOrEmpty(config))
                {
                    throw new ArgumentNullException("config");
                }
                if (string.IsNullOrEmpty(resolver))
                {
                    throw new ArgumentNullException("resolver");
                }
                Resolution resolution = new Resolution();
                try
                {
                    dictionary = ResolveSQL(config, resolver, resolution);
                }
                catch (Exception exception)
                {
                    EventLogger.Write(MethodBase.GetCurrentMethod(), exception);
                    throw;
                }
                return dictionary;
            }
            catch (Exception ex)
            {
                // Insert Custom Logging Here
                throw (ex);
            }
        }

        Dictionary<string, string> IResolveProvider.Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
        {
            try
            {
                Dictionary<string, string> dictionary;
                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");
                }
                Resolution resolution = new Resolution();
                try
                {
                    ResolverMgr.SetContext(resolution, message, pipelineContext);
                    dictionary = ResolveSQL(config, resolver, resolution);
                }
                catch (Exception exception)
                {
                    throw (exception);
                }
                return dictionary;
            }
            catch (Exception ex)
            {
                // Insert Custom Logging Here
                throw (ex);
            }
        }

        public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
        {
            try
            {
                Dictionary<string, string> dictionary;
                if (message == null)
                {
                    throw new ArgumentNullException("message");
                }
                Resolution resolution = new Resolution();
                try
                {
                    ResolverMgr.SetContext(resolution, message);
                    dictionary = ResolveSQL(resolverInfo.Config, resolverInfo.Resolver, resolution);
                }
                catch (Exception exception)
                {
                    throw (exception);
                }
                finally
                {
                    if (resolution != null)
                    {
                        resolution = null;
                    }
                }
                return dictionary;
            }
            catch (Exception ex)
            {
                // Insert Custom Logging Here
                throw (ex);
            }
        }

        #endregion

– Next up we need to write our code to fetch our results. I’ve just hooked into the static resolver props here for demo purposes. For real world implementation we would also implement caching so as to avoid hitting SQL on each pass.

private static Dictionary<string, string> ResolveSQL(string config, string resolver, Resolution resolution)
        {
            Dictionary<string, string> dictionary3;
            Microsoft.Practices.ESB.Resolver.STATIC.STATIC @static = new Microsoft.Practices.ESB.Resolver.STATIC.STATIC();
            Dictionary<string, string> facts = null;
            Dictionary<string, string> resolverDictionary = new Dictionary<string, string>();

            if (!resolver.Contains(@":\"))
            {
                resolver = resolver + @":\";
            }
            try
            {
                facts = ResolverMgr.GetFacts(config, resolver);
                @static.MessageExchangePattern = "two-way";
                @static.JaxRpcResponse = false;

                string sendLocationKey = string.Empty;

                // Get the key from the itinerary resolver
                sendLocationKey = ResolverMgr.GetConfigValue(facts, false, "SendLocationKey");

                SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ToString());
                connection.Open();

                SqlDataAdapter adapter = new SqlDataAdapter();

                // Get endpoint config from SQL
                adapter.SelectCommand = new SqlCommand("<Add SQL Here to get facts>", connection);

                DataSet sendLocations = new DataSet();
                adapter.Fill(sendLocations);

                @static.EndpointConfig = "<from sql>";
                @static.TransportLocation = "<from sql>";
                @static.TransportType = "<from sql>";

                connection.Close();

                // Get the remainder from the itinerary
                @static.Action = ResolverMgr.GetConfigValue(facts, false, "Action");
                string str = ResolverMgr.GetConfigValue(facts, false, "JaxRpcResponse");
                string str2 = ResolverMgr.GetConfigValue(facts, false, "MessageExchangePattern");
                @static.TargetNamespace = ResolverMgr.GetConfigValue(facts, false, "TargetNamespace");
                @static.TransformType = ResolverMgr.GetConfigValue(facts, false, "TransformType");
                if (!string.IsNullOrEmpty(str) && ((string.Compare(str, "true", true, CultureInfo.CurrentCulture) == 0) || (string.Compare(str, "false", true, CultureInfo.CurrentCulture) == 0)))
                {
                    @static.JaxRpcResponse = Convert.ToBoolean(str, NumberFormatInfo.CurrentInfo);
                }
                if (!string.IsNullOrEmpty(str2) && ((str2 == "two-way") || (str2 == "one-way")))
                {
                    @static.MessageExchangePattern = str2;
                }
                ResolverMgr.SetEndpointProperties("TransportType", @static.TransportType, resolution);
                ResolverMgr.SetEndpointProperties("TransportLocation", @static.TransportLocation, resolution);
                ResolverMgr.SetEndpointProperties("Action", @static.Action, resolution);
                ResolverMgr.SetEndpointProperties("EndpointConfig", @static.EndpointConfig, resolution);
                ResolverMgr.SetEndpointProperties("JaxRpcResponse", @static.JaxRpcResponse.ToString(), resolution);
                ResolverMgr.SetEndpointProperties("MessageExchangePattern", @static.MessageExchangePattern, resolution);
                ResolverMgr.SetEndpointProperties("TargetNamespace", @static.TargetNamespace, resolution);
                ResolverMgr.SetEndpointProperties("TransformType", @static.TransformType, resolution);

                resolverDictionary = new Dictionary<string, string>();
                ResolverMgr.SetResolverDictionary(resolution, resolverDictionary);
                dictionary3 = resolverDictionary;

                catch (Exception ex)
                {
                    System.Diagnostics.Trace.Write(ex.ToString());
                    throw;
                }
                finally
                {
                    if (resolution != null)
                    {
                        resolution = null;
                    }
                    if (@static != null)
                    {
                        @static = null;
                    }
                    if (facts != null)
                    {
                        facts.Clear();
                        facts = null;
                    }
                    if (resolverDictionary != null)
                    {
                        resolverDictionary = null;
                    }
                }

            return dictionary3;
        }
    }

– Now we need to compile, GAC, and register our new resolver. To register add the below setting to the esb.config file under the resolvers section. Note the name attribute. Your itinerary xml should have a resolver that is prefixed with the moniker SQL://. You can either update the itinerary xml after its exported from the itinerary designer or write an itinerary designer extension. There is a good SDK sample on exactly this.

    <resolver name="SQL" type="Resolvers.SQL.ResolveProvider, Resolvers.SQL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c94de1b0c8c3bfff">
Advertisements
This entry was posted in BizTalk Server. Bookmark the permalink.

One Response to ESB Toolkit : Custom Endpoint Resolver

  1. Pingback: ESB Toolkit RetryCount and RetryInterval | Microsoft Tech

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