How To: Write a BizTalk Application Configuration Wizard

We have a BizTalk Application to be deployed on some environment, however, the deploy team is not familiar with BizTalk Administrator Console. And sometimes they make things worse even with a detailed deployment guideline. Then we decide to write a wizard.
To Begin with the wizard, it's better list all we have to set up for the BizTalk application:
1. Three web services
2. Three custom BizTalk adapters
3. A 32 bit host instance for SQL and FTP adapter
4. A SQL Server database
Then we can go with the main application import process:
1. Import the .msi application and install it on the server
2. Import the individual binding file for the application
3. Update the port configuration for the application
4. Start the application
If we have incremental update, we have to redo the import process(That's depends on the update).
Below will the code we use for all the function listed:
Step One: Create Web Service
For this function, we packaged the complied web services, we ask the path of the web services folder, then the wizard set up a pool with BizTalk Isolate account, and binding the three web services with the app pool we created.
Code herein:

View Code
public class IIS7Management
{
public static void CreateAppPool(string AppPoolName, string User, string password)
{
ServerManager mgr = new ServerManager();

var app = mgr.ApplicationPools.First(s => s.Name == AppPoolName);
if (app == null)
{
// Add a new application pool called PoolName
ApplicationPool myAppPool = mgr.ApplicationPools.Add(AppPoolName);

// Set the runtime version of ASP.NET to 4.0
myAppPool.ManagedRuntimeVersion = "v4.0";

// Use the Classic Pipeline mode
myAppPool.ManagedPipelineMode = ManagedPipelineMode.Classic;

// Configure my new app pool to start automatically.
myAppPool.AutoStart = true;

// What action should IIS take when my app pool exceeds
// the CPU limit specified by the Limit property
myAppPool.Cpu.Action = ProcessorAction.NoAction;

// Use the SpecificUser account
myAppPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
myAppPool.ProcessModel.UserName = User;
myAppPool.ProcessModel.Password = password;

// Shut down after being idle for 5 minutes.
myAppPool.ProcessModel.IdleTimeout = TimeSpan.FromMinutes(5);

// Max. number of IIS worker processes (W3WP.EXE)
myAppPool.ProcessModel.MaxProcesses = 1;

// Commit the changes
mgr.CommitChanges();
}
}

public static void CreateApplication(string AppPoolName, string AppName, string physicalPath)
{
try
{
ServerManager mgr = new ServerManager();
Application myapp = mgr.Sites["Default Web Site"].Applications.Add("/" + AppName, physicalPath);
myapp.ApplicationPoolName = AppPoolName;
mgr.CommitChanges();
}
catch(Exception ex)
{
throw ex;
}
}
}

Step Two: Install Adapters:
From here we have to install the Adapters and Add these adapters into BizTalk.
We use a process to install the adapters and wait until it finished then we add this into BizTalk.

Code here

View Code
public static void CreateAdapter(string Name, string AdapterCLSID, string comment)
{
try
{
PutOptions options = new PutOptions();
options.Type = PutType.UpdateOrCreate;

//create a ManagementClass object and spawn a ManagementObject instance
ManagementClass objAdapterClass = new ManagementClass("root\\MicrosoftBizTalkServer", "MSBTS_AdapterSetting", null);
ManagementObject objAdapter = objAdapterClass.CreateInstance();

//set the properties for the Managementobject
objAdapter.SetPropertyValue("Name", Name);
objAdapter.SetPropertyValue("MgmtCLSID", AdapterCLSID);
objAdapter.SetPropertyValue("Comment", comment);

objAdapter.Put(options);
}
catch (Exception excep)
{
throw excep;
}

}

Step Three: Create Host Instance and update the adapters.

We use the assembly in Microsoft.BizTalk.ExplorerOM to create host and host instance.

Code here:

View Code
public static void CreateHost(string HostName, int HostType, string NTGroupName, bool IsHost32BitOnly, bool HostTracking)
{
try
{
PutOptions options = new PutOptions();
options.Type = PutType.CreateOnly;

//create a ManagementClass object and spawn a ManagementObject instance
ManagementClass objHostSettingClass = new ManagementClass("root\\MicrosoftBizTalkServer", "MSBTS_HostSetting", null);
ManagementObject objHostSetting = objHostSettingClass.CreateInstance();

ManagementObject objHostSetting1 = new ManagementObject();
objHostSetting1.Scope = new ManagementScope("root\\MicrosoftBizTalkServer");

//define lookup query
string strQuery = "MSBTS_HostSetting.Name='BizTalkServerApplication'";
objHostSetting1.Path = new ManagementPath(strQuery);

//set the properties for the Managementobject
objHostSetting["Name"] = HostName;
objHostSetting["HostType"] = HostType;
if (NTGroupName == "")
{
//redefine properties value
objHostSetting["NTGroupName"] = objHostSetting1["NTGroupName"];
}
else
{
objHostSetting["NTGroupName"] = NTGroupName;
}

objHostSetting["AuthTrusted"] = objHostSetting1["AuthTrusted"];

objHostSetting["IsHost32BitOnly"] = IsHost32BitOnly;
objHostSetting["HostTracking"] = HostTracking;

//create the Managementobject
objHostSetting.Put(options);
}
catch (Exception excep)
{
System.Console.WriteLine("CreateHost - " + HostName + " - failed: " + excep.Message);
}
}

public static void CreateHostInstance(string HostName, string username, string password)
{
try
{
PutOptions options = new PutOptions();
options.Type = PutType.CreateOnly;

//create a ManagementClass object and spawn a ManagementObject instance
ManagementClass objHostClass = new ManagementClass("root\\MicrosoftBizTalkServer", "MSBTS_ServerHost", null);
ManagementObject objHost = objHostClass.CreateInstance();

//set the properties for the Managementobject
objHost["HostName"] = HostName;
objHost["ServerName"] = System.Environment.MachineName;
objHost.InvokeMethod("Map", null);

ManagementClass objHostClass2 = new ManagementClass("root\\MicrosoftBizTalkServer", "MSBTS_HostInstance", null);
ManagementObject objHostInstance = objHostClass2.CreateInstance();
objHostInstance["Name"] = "Microsoft BizTalk Server " + System.Environment.MachineName + "" + RuntimeGlobal.BiztalkServerName;

object[] args = new object[2];
args[0] = username;
args[1] = password;

objHostInstance.InvokeMethod("Install", args);

}
catch (Exception excep)
{
System.Console.WriteLine("CreateHost - " + HostName + " - failed: " + excep.Message);
}

}

After this, we have to update the host name of the adapter handles:

View Code
public static void UpdateHandler(string AdapterName, string HostName, string HostNameToSwitchTo)
{
try
{
PutOptions options = new PutOptions();
options.Type = PutType.UpdateOnly;

//Look for the target WMI Class MSBTS_ReceiveHandler instance
string strWQL = "SELECT * FROM MSBTS_ReceiveHandler WHERE AdapterName =\"" + AdapterName + "\" AND HostName = \"" + HostName + "\"";
ManagementObjectSearcher searcherHandler = new ManagementObjectSearcher(new ManagementScope("root\\MicrosoftBizTalkServer"), new WqlObjectQuery(strWQL), null);

if (searcherHandler.Get().Count > 0)
foreach (ManagementObject objReceiveHandler in searcherHandler.Get())
{
//update host association
objReceiveHandler["HostNameToSwitchTo"] = HostNameToSwitchTo;
//update the ManagementObject
objReceiveHandler.Put(options);
}

strWQL = "SELECT * FROM MSBTS_SendHandler2 WHERE AdapterName =\"" + AdapterName + "\" AND HostName = \"" + HostName + "\"";
searcherHandler = new ManagementObjectSearcher(new ManagementScope("root\\MicrosoftBizTalkServer"), new WqlObjectQuery(strWQL), null);

if (searcherHandler.Get().Count > 0)
foreach (ManagementObject objSendHandler in searcherHandler.Get())
{
//update host association
objSendHandler["HostNameToSwitchTo"] = HostNameToSwitchTo;
//update the ManagementObject
objSendHandler.Put(options);
}

}
catch (Exception excep)
{
System.Console.WriteLine("UpdateReceiveHandler - " + AdapterName + "" + HostName + " - failed: " + excep.Message);
}
}


Last Step: Create the SQL Server DB:

Code Here:

View Code
private void CreateSQLDataBase(string connString, string cmdString)
{
SqlConnection myConn = new SqlConnection(connString);

SqlCommand myCommand ;
try
{
myConn.Open();
foreach (string command in SplitSqlCommands(cmdString))
{
if (command != "")
{
myCommand = new SqlCommand(command, myConn);
myCommand.ExecuteNonQuery();
}
}
MessageBox.Show("DataBase is Created Successfully", "Success");
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString(), "Error");
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
}

}

private IEnumerable<string> SplitSqlCommands(string commandText)
{
IEnumerable<string> commands = commandText.Split(new string[] { "\r\nGO\r\n", "\r\nGo\r\n", "\r\ngo\r\n", "\r\ngO\r\n" },
StringSplitOptions.None);
return commands;
}



Now, all the prepare works are done. We are ready to import the Biztalk Application.

To import the msi and install it on the server:

Code Here:

View Code
            BTSManagement.StopApplication(APPName);
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
string targetPath = System.Environment.GetEnvironmentVariable("BTSINSTALLPATH").ToString();
p.StandardInput.WriteLine(targetPath.Substring(0, 2));
p.StandardInput.WriteLine("cd " + targetPath);

p.StandardInput.WriteLine("BTSTask ImportApp /Package:\"" + MSIPath + "\" /Environment:Default /ApplicationName:" + APPName + "/Overwrite");

p.StandardInput.WriteLine("exit");

string strRst = p.StandardOutput.ReadToEnd();
System.IO.File.WriteAllText(@"C:\BTSImportlog.txt", strRst);
// if end
p.Close();

Process p1 = new Process();
p1.StartInfo.FileName = "msiexec.exe";
p1.StartInfo.Verb = "runas";
p1.StartInfo.Arguments = "/i \"" + MSIPath + "\" /qr";
p1.StartInfo.CreateNoWindow = false;
p1.Start();
p1.WaitForExit();

BTSManagement.StartApplication("NNA");
MessageBox.Show("MSI Import finished, Log File at " + @"C:\BTSImportlog.txt", "Information");

Then import the binding:

Code Here:

View Code
            BTSManagement.StopApplication(AppName);
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
string targetPath = System.Environment.GetEnvironmentVariable("BTSINSTALLPATH").ToString();
p.StandardInput.WriteLine(targetPath.Substring(0, 2));
p.StandardInput.WriteLine("cd " + targetPath);

p.StandardInput.WriteLine("BTSTask ImportBindings /ApplicationName:" + AppName +" /Source:\"" + bindingPath + "\"");
p.StandardInput.WriteLine("exit");

string strRst = p.StandardOutput.ReadToEnd();
System.IO.File.WriteAllText(@"C:\BTSImportlog.txt", strRst);
// if end
p.Close();
BTSManagement.StartApplication(AppName);
MessageBox.Show("Binding Import finished, Log File at " + @"C:\BTSImportlog.txt", "Information");

Then update the ports configuration:

View Code
public static void UpdateReceiveLocation(string ReceivePort, string ReceiveLocationName, string Address)
{
BtsCatalogExplorer catalog = new BtsCatalogExplorer();
catalog.ConnectionString = RuntimeGlobal.ConnectString;
try
{
ReceiveLocation loc = catalog.ReceivePorts[ReceivePort].ReceiveLocations[ReceiveLocationName];
loc.Address = Address;

// persist changes to BizTalk configuration database
catalog.SaveChanges();
}
catch (Exception e)
{
catalog.DiscardChanges();
throw e;
}
}

public static void UpdateSendPort(string SendPort, string Address)
{
BtsCatalogExplorer catalog = new BtsCatalogExplorer();
catalog.ConnectionString = RuntimeGlobal.ConnectString;
try
{
SendPort myStaticOnewaySendPort = catalog.SendPorts[SendPort];
myStaticOnewaySendPort.PrimaryTransport.Address = Address;

// persist changes to BizTalk configuration database
catalog.SaveChanges();
}
catch (Exception e)
{
catalog.DiscardChanges();
throw e;
}
}


To start/Stop the BizTalk Application:

View Code
public static void StartApplication(string AppName)
{
BtsCatalogExplorer catalog = new BtsCatalogExplorer();
catalog.ConnectionString = RuntimeGlobal.ConnectString;

Application app = catalog.Applications[AppName];
if (app != null)
{
app.Stop(ApplicationStopOption.StopAll);
}
app.Start(ApplicationStartOption.StartAll);
}

public static void StopApplication(string AppName)
{
BtsCatalogExplorer catalog = new BtsCatalogExplorer();
catalog.ConnectionString = RuntimeGlobal.ConnectString;

Application app = catalog.Applications[AppName];
if (app != null)
{
app.Stop(ApplicationStopOption.StopAll);
}
}


The RuntimeGlobal is here:

View Code
public class RuntimeGlobal
{
///<summary>
/// Query information from BizTalk MgmtDB
///</summary>
///<param name="strCmd">string strCmd = string.Format("SELECT a.uidGUID, b.OutboundEngineCLSID FROM bts_sendport a,adm_Adapter b WHERE a.nvcName = '{0}' and b.Name = '{1}'", "DynamicSendToDMS", "WCF-Custom");</param>
///<returns></returns>
public static string[] GetBizTalkConfigValue(string strCmd)
{
string[] result = null;
SqlCommand command = new SqlCommand(strCmd, GetConnection())
{
CommandType = CommandType.Text,
CommandTimeout = 60
};
SqlDataReader sdr = command.ExecuteReader();
while (sdr.Read())
{
result = new string[sdr.FieldCount];
for (int i = 0; i < sdr.FieldCount; i++)
result[i] = sdr[i].ToString();
break;
}
return result;
}

private static string m_BtsDBServer;
private static string m_BtsDBName;

private static string BiztalkMgmtDbname
{
get
{
if (m_BtsDBName == null)
{
m_BtsDBName = GetBiztalkRegistryKeyValue("MgmtDBName");
}
return string.Format(CultureInfo.InvariantCulture, m_BtsDBName, new object[0]);
}
}

public static string BiztalkServerName
{
get
{
if (m_BtsDBServer == null)
{
m_BtsDBServer = GetBiztalkRegistryKeyValue("MgmtDBServer");
}
return string.Format(CultureInfo.InvariantCulture, m_BtsDBServer, new object[0]);
}
}

private static string GetBiztalkRegistryKeyValue(string keyName)
{
return (string)Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\BizTalk Server\3.0\Administration").GetValue(keyName);
}

private static SqlConnection GetConnection()
{
SqlConnection connection = new SqlConnection
{
ConnectionString = string.Format(CultureInfo.InvariantCulture,
"Server={0};integrated security=SSPI",
new object[] { BiztalkServerName })
};
connection.Open();
connection.ChangeDatabase(BiztalkMgmtDbname);
return connection;
}

public static string ConnectString
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"Server={0};integrated security=SSPI;Initial Catalog={1}",
BiztalkServerName,
BiztalkMgmtDbname);
}

}
}


Ok, now all the work is done. We add some UI for all the action needed.

The deployment team then use this to deploythe BizTalk application and everything goes well.

I think many of the BizTalk guys will meet this so I write it here, and hope it's helpful.

原文地址:https://www.cnblogs.com/JasonLiao/p/2265026.html