Developing custom tools for BizTalk

Listen with webReader
Published 14 December 09 12:10 PM | wmmihaa

For the last four months I’ve been developing a benchmarking tool for BizTalk which is going to be released soon. However, I thought I’d share some of the pain you might run into while developing custom tooling for BizTalk.

The problem lies with communicating with BizTalk, where you’re pretty much left with two options; Microsoft.BizTalk.ExplorerOM (EOM) or WMI. First of all, each option is suitable for different purposes. If you want to manage ports and applications, ExplorerOM would be your best bet, where as if you’d like to manage hosts, host instances or handlers, WMI would be your only option.

The problem I ran into, is that neither one of these works if you are not running this from a BizTalk Server, which in some cases is not preferred.

The problem occurs where the user tries to start a port from the custom application and therefore needs to commit using the SaveChanges operation (EOM). In the worst scenario, the user is running the app from a server/desktop where BizTalk is not installed. BizTalk and SQL are installed on separate boxes.

Using EOM won’t work as it throws an “Object reference not set to an instance of an object” exception (see code below). This is because EOM require BizTalk to be installed on the same box, even though it doesn’t necessarily need to be part of the group you’re trying to connect to.   

 

static void Main(string[] args)
{
    Console.WriteLine("Server name?");
    string server = Console.ReadLine();

    BtsCatalogExplorer explorer = new BtsCatalogExplorer();
    explorer.ConnectionString = new SqlConnectionStringBuilder()
    {
        DataSource = server,
        InitialCatalog = "BizTalkMgmtDb",
        IntegratedSecurity = true
    }.ConnectionString;

    Console.WriteLine("Connected..."); // This works!

    try
    {
        explorer.SaveChanges(); // This fails!
        Console.WriteLine("SaveChanges were executed without exceptions.");
    }
    catch (Exception ex)
    {
        Console.WriteLine("An error occurd...");
        Console.WriteLine(ex.Message);
    }
    Console.WriteLine("\nPress any key to close...");
    Console.ReadKey();
}

 

Using WMI won’t work because of the  “double-hop authentication issue”, where credentials will be lost on the second jump (to SQL). This will result in a “Anonymous user does not have access …blah blah blah” – SQL exception. http://www.microsoft.com/technet/scriptcenter/resources/wmifaq.mspx#EXLAC

clip_image001

I’d really like to see the product team to ship BizTalk with a Management Application, exposing services for the most common tasks.

Filed under: , ,

Comments

# Richard Hallgren said on December 14, 2009 03:53 PM:

Very true ... This is definitively a pain point.

I guess they have a start in the ESB Operations Web services (msdn.microsoft.com/.../ee264368(BTS.10).aspx).

But I really look forward to see how much PowerShell support they manage to squeeze in to 2009 r2! That should hopefully help on issues like this.

# Jan Odegard said on December 14, 2009 06:09 PM:

Nice article on where we've all ended up sooner or later. Can't wait to get better support for writing custom tools using PowerShell (hopefully).

# Randal van Splunteren said on December 15, 2009 10:58 AM:

Hi Mikael,

Good post. I also agree with you and the other people that wrote a comment that this can be very painfull.

To deal with the problem of multiple api's to manage BizTalk we developed a wrapper layer. This layer provides one uniform interface for managing BizTalk. We also write a powershell provider on top of this. The provider has a lot of builtin cmdlets to manage biztalk.

see: http:///psbiztalk.codeplex.com

By the way I think the other two team members on the codeplex site are your colleagues! :-)

Regards,

Randal van Splunteren

# Gordon said on February 8, 2010 09:19 PM:

Hello Mikael,

thanks for your post. Today I encountered the same problems on the need to remote manage host instances via WMI. Currently I'm preparing a performance lab and wanted to test our scripts on a 3 box deployment *peng*. Anyway I'm feeling - thanks to your post - a little bit better that others have the same probs, I can stop trying harder via WMI and for that I must consider other ways.

What do you mean by:

Using WMI won’t work because of the  “double-hop authentication issue”, where credentials will be lost on the second jump (to SQL). This will result in a “Anonymous user does not have access …blah blah blah” – SQL exception. www.microsoft.com/.../wmifaq.mspx

I also found this information prior to your post and tried their suggestions; which did not work resp. I couldn't get to work. My problem is still: The infos supplied by MS do not 100%: Dies does not work.

I will digg a little bit deeper into the BizTalk Administration Console assemblies. The console installed on the SQL box (no full bts installation) is capable of remote managing the host instances on the bts boxes. So there should be a way.

Regards,

Gordon

# Gordon said on February 10, 2010 12:31 AM:

Hello Mikael,

I got it working for my scenario. With having installed the BizTalk Administrator Console features on my load- and performance measuring server, I'm capable to remote start/stop remote bts host instances. I'm using the Microsoft.BizTalk.SnapIn.Framework dll found within the BizTalk installation dir (Programs...BizTalk...).

After some Reflector sessions here is my code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System;

using System.Xml;

using System.Management;

using BizUnit;

using BizUnit.BizUnitOM;

using Microsoft.BizTalk.SnapIn.Framework;

namespace ************.Performance.BizUnitExtensions

{

   /// <summary>

   /// Base class for host instances involved test steps.

   /// </summary>

   public abstract class HostInstanceStepBase : ITestStepOM

   {

       public void Execute(XmlNode testConfig, Context context)

       {

           var bizTalkMgmtDbServer = context.ReadConfigAsString(testConfig, "BizTalkMgmtDbServer");

           var bizTalkMgmtDbName = context.ReadConfigAsString(testConfig, "BizTalkMgmtDbName");

           var server = context.ReadConfigAsString(testConfig, "HostInstanceServer");

           var hostName = context.ReadConfigAsString(testConfig, "HostInstanceName");

           var action = GetAction(testConfig, context);

           Execute(action, GetHostInstanceWmiObject(bizTalkMgmtDbServer, bizTalkMgmtDbName, server, hostName), context);

       }

       protected virtual void Execute(Func<ManagementObject, bool> action, ManagementObject hostInstanceMgmtObj, Context context)

       {

           action(hostInstanceMgmtObj);

       }

       protected abstract Func<ManagementObject, bool> GetAction(XmlNode testConfig, Context context);

       public static ManagementObject GetHostInstanceWmiObject(string mgmtDbServer, string mgmtDb, string server, string hostName)

       {

           var wmiProvider = new WmiProvider(mgmtDbServer, mgmtDb);

           ManagementObjectCollection mgmtObjs = wmiProvider.SelectRemote("MSBTS_HostInstance", "ClusterInstanceType=0 or ClusterInstanceType=1 or ClusterInstanceType=2");

           foreach (ManagementObject each in mgmtObjs)

           {

               if (((string)each["HostName"]) != hostName)

               {

                   continue;

               }

               if (((string)each["RunningServer"]) != server)

               {

                   continue;

               }

               return each;

           }

           var msg = string.Format("Could not find the host instance {0} on the running server {1}.", hostName, server);

           throw new Exception(msg);

       }

       public void Execute(Context context)

       {

           throw new NotImplementedException();

       }

       public void Validate(Context context)

       {

           throw new NotImplementedException();

       }

   }

}

GetAction is implemented by subclasses returning the kind of strategy to be applied (in my case start/stop host instances and checking instances whether they have been started correctly; start/stop as usually done in case of bts through wmi).

BizTalkMgmtDbServer := SQL Server of BizTalkMgmtDb

BizTalkMgmtDbName := Name of BizTalkMgmtDb

HostInstanceServer := Server of the desired host instance

HostInstanceName := Host instance name

I haven't checked yet my "solution" without the BizTalk Administrator Console installation on a plain box with just the needed assemblies. It just works for my scenario

Sorry for my bad english.

Regards,

Gordon

# wmmihaa said on February 10, 2010 07:17 PM:

Gordon,

How do you make use of the Microsoft.BizTalk.SnapIn.Framework dll assembly? I don

t see it in your code.

Are you executing this from a server separate from your bts group?

# Gordon said on February 10, 2010 11:32 PM:

Hello Mikael,

first sorry that much code. The essential part would have been sufficient. I don't participate that much in any *new communication technologies*. I'll learn... But it's also difficult to resist exchanging with bts developers (I don't know that many)...

The Microsoft.BizTalk.SnapIn.Framework dll comes into the game here:

public static ManagementObject GetHostInstanceWmiObject(string mgmtDbServer, string mgmtDb, string server, string hostName)

      {

  var wmiProvider = new WmiProvider(mgmtDbServer, mgmtDb);

          ManagementObjectCollection mgmtObjs = wmiProvider.SelectRemote("MSBTS_HostInstance", "ClusterInstanceType=0 or ClusterInstanceType=1 or ClusterInstanceType=2");

        ...

"WmiProvider" is "the one class" I'm using from the BizTalk snap-in framework dll. The following code/application is as usual to WMI (except of any using statements / best habits etc.; but not needed in my case).

I can't really tell you whether my executing server is separated from the actual bts servers - I guess yes (but you never know for sure what is under the MS hood...). At least my executing server does not run any bts host instances involved in the actual "solution's work". The server has just installed the stuff for being able to run the BizTalk Administration Console (and the other stuff; as EntSSO... different story as well as generating all our test scripts through T4 -> managing the complexity of highly varying testing scenarios) for that I can connect from my "performance script executing server" to any (changing) bts group.

I haven't tried yet taking the corresponding dll to a plain new server to remote manage any host instances without the other bts stuff (maybe on weekend; for that there are really no other dependencies). Currently I have the solution that I wanted: I can switch between performance measuring a single server deployment as well as differently distributed deployments quite easy from and with the same performance measuring scripts/server. I.e., we are going to test 3 different deployment scenarios (with scaled out + up variations) during our performance lab (three product variations) and I didn't want to manage each of those scenarios by dedicated scripts (now all in one) and executing servers (now just one).

Regards,

Gordon

# wmmihaa said on February 11, 2010 04:21 PM:

using the code you sent, I get "Cannot connect to WMI provider. Ensure that the WMI service is running." when running this from my desktop with no biztalk installed. But it works on the BizTalk box.

I only added referense to the Microsoft.BizTalk.SnapIn.Framework dll and the Microsoft.BizTalk.Tracing dll. Do I need to do anything else?

This Blog

News

    MVP - Microsoft Most Valuable Professional BizTalk User Group Sweden BizTalk blogdoc

    Follow me on Twitter Meet me at TechEd

    Visitors

    Locations of visitors to this page

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Syndication