Thursday, August 8, 2013

MBV checks for orphan instances disabled

The Message Box Viewer (MBV) checks for orphan instances were disabled in our live environment, that is they were not run. The MBV reports said:

"BizTalk - DTA Db : Orphaned Svc Instances  (SQL Query, 2 Rules, Disabled, can not be executed in a multiple MsgBox config or if MsgBox db not located on same server than DTA db)"

However, we are not having a multiple messagebox configuration and our messagebox database is located on same server as the tracking (DTA) database.

However, testing shows that the problem is caused by what seems to be a case sensitive string comparison between the messagebox database and the tracking database. If there isn't an exact match, the orphan check will not be run.

In our case we have different dns-names pointing to the messagebox database and the tracking database respectively, but the databases are on the same server/instance.

As I understand the MBV license the  LIMITATIONS ON REVERSE ENGINEERING, DECOMPILATION, AND DISASSEMBLY mean that you cannot use say .Net Reflector to find the exact cause of the problem - let alone fix it yourself :-(

Maybe this tool should be moved to Open Source?

I hope Microsoft will do a hotfix MBV (version 12 and 13) where the case sensitive string comparison is changed into a comparison along these lines:

private bool MessageBoxAndTrackingDbOnDifferentServers()
{
    if (String.Compare(MSGBOXDBServer, DTADBServer, StringComparison.OrdinalIgnoreCase) == 0)
    {
        return false;
    }

    var seperators = new[] { '\\', ':' };

    foreach (var seperator in seperators)
    {
        var msgboxServerSplit = MSGBOXServer.Split(seperator);
        var dtaServerSplit = DTADBServer.Split(seperator);

        if (msgboxServerSplit.Length != 2 || dtaServerSplit.Length != 2) continue;

        if (String.Compare(msgboxServerSplit[1], dtaServerSplit[1], StringComparison.OrdinalIgnoreCase) != 0)
        {
            return true;
        }

        if (GetAddress(msgboxServerSplit[0]) != GetAddress(dtaServerSplit[0]))
        {
            return true;
        }
    }
            
    return false;
}

This code allow different casing as well as different dns-names as long as they point to the same ip-address.

GetAddress is pretty much stolen from the msdn ping sample:

public static string GetAddress(string server)
{
    var pingSender = new Ping();
    var options = new PingOptions {DontFragment = true};

    // Use the default Ttl value which is 128, 
    // but change the fragmentation behavior.

    // Create a buffer of 32 bytes of data to be transmitted. 
    const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    var buffer = Encoding.ASCII.GetBytes(data);
    const int timeout = 120;
            
    var reply = pingSender.Send(server, timeout, buffer, options);
            
    if (reply != null && reply.Status == IPStatus.Success)
    {
        return reply.Address.ToString();
    }

    return Guid.NewGuid().ToString();
}