Multiple bindings files

Topics: Bindings File, Settings Management and SSO
Feb 17, 2012 at 10:12 PM

We have multiple projects within our solution organized by functional area: Orders, Items, Shipping, etc.  Within each of these we then use subfolders for schemas, orchestrations, etc.  Each project becomes its own assembly.  We have multiple developers that have ownership for given projects.  They deploy and test in their own sandbox environments.  When all is said and done, each developer is responsible for exporting their bindings for a project from BizTalk and putting them back into TFS.  That means that we have many bindings files in TFS that support the single solution.  I am trying to automate the building of a single MSI with bindings to deploy without having to go through a manual process of bringing all the bindings into a BizTalk run-time first.

I am new to BTDF and it is an awesome tool.  I can't figure out how to incorporate (in an automated fashion) multiple bindings into the process when I build a server MSI.  Is this possible?  If so, how would I go about doing that?

Thanks ahead of time for your assistance.

Regards,

Keith

Coordinator
Feb 27, 2012 at 7:49 AM

Hi Keith,

Currently the Deployment Framework expects a single binding file.  There is an extension point in the server MSI build process that you could use to bring the multiple binding files together into one: create a custom Target in your .btdfproj named CustomPreRedist.  When that target executes, your goal would be to create the file PortBindings.xml (or PortBindingsMaster.xml if you're using a master bindings file) in the deployment project folder, and it would subsequently be picked up and packaged into the MSI.

How to bring them together?  One idea is to use XSLT.  You could either write a custom MSBuild task that does the job (takes in an ItemGroup list of the various binding files and outputs the combined file), or even a simple .NET console app to call with the Exec task.

Does that help?

Thanks,
Tom

Feb 28, 2012 at 6:48 PM

Tom,

Thanks for the response.  I came up with a solution whereby I use the xml-preprocess to go through a master list of include statements such as the ones below:

<?xml version="1.0" encoding="utf-8"?>
<BindingInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Assembly="Microsoft.BizTalk.Deployment, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Version="3.5.1.0" BindingStatus="FullyBound" BoundEndpoints="12" TotalEndpoints="12">
  <Timestamp>2012-02-21T14:57:26.2707826-05:00</Timestamp>
  <ModuleRefCollection>
    <!-- #include "..\Tervis.Biztalk.Accounts\Bindings\Tervis.Integration.EmunCustomerAccount_Inbound.BindingInfo.xml"
        xpath="/BindingInfo/ModuleRefCollection" -->
    <!-- #include "..\Tervis.Biztalk.Customers\Bindings\Tervis.BizTalk.Customers.BindingInfo.xml"
        xpath="/BindingInfo/ModuleRefCollection" -->
    <!-- #include "..\Tervis.Biztalk.PurchaseOrders\Bindings\Tervis.BizTalk.PurchaseOrders.BindingInfo.xml"
        xpath="/BindingInfo/ModuleRefCollection" -->
  </ModuleRefCollection>
  <SendPortCollection>
    <!-- #include "..\Tervis.Biztalk.Accounts\Bindings\Tervis.Integration.EmunCustomerAccount_Inbound.BindingInfo.xml"
        xpath="/BindingInfo/SendPortCollection" -->
    <!-- #include "..\Tervis.Biztalk.Customers\Bindings\Tervis.BizTalk.Customers.BindingInfo.xml"
        xpath="/BindingInfo/SendPortCollection" -->
    <!-- #include "..\Tervis.Biztalk.PurchaseOrders\Bindings\Tervis.BizTalk.PurchaseOrders.BindingInfo.xml"
        xpath="/BindingInfo/SendPortCollection" -->
  </SendPortCollection>
  <DistributionListCollection />
  <ReceivePortCollection>
    <!-- #include "..\Tervis.Biztalk.Accounts\Bindings\Tervis.Integration.EmunCustomerAccount_Inbound.BindingInfo.xml"
        xpath="/BindingInfo/ReceivePortCollection" -->
    <!-- #include "..\Tervis.Biztalk.Customers\Bindings\Tervis.BizTalk.Customers.BindingInfo.xml"
        xpath="/BindingInfo/ReceivePortCollection" -->
    <!-- #include "..\Tervis.Biztalk.PurchaseOrders\Bindings\Tervis.BizTalk.PurchaseOrders.BindingInfo.xml"
        xpath="/BindingInfo/ReceivePortCollection" -->
  </ReceivePortCollection>
  <PartyCollection xsi:nil="true" />
</BindingInfo>

This needs to be done on Build, not deploy.  Deploy will not have the source bindings files.  So I need a pre-process for build to merge the files, and then a pre-process on deploy to apply the EnvironmentSettings.

If I run this without the /c flag and without referencing a SettingsFile it merges together many bindings, does not remove the xml pre-process comments, but does replace the variables with errors about not finding the variables to substitute.  I'm not sure I care that it does that because when during deploy they will be replaced with values from the EnvironmentSettings.

But if I add a CustomReDist will that only occur on build?  I don't want it to try to run again on deploy, because again, the source bindings files will not be on the machine being deployed and if it looks to find them to replace it will produce errors.

Thoughts?

Keith

Coordinator
Feb 28, 2012 at 7:38 PM

Hi Keith,

Great, that's a clever solution to the problem.  You're OK -- CustomRedist and CustomPreRedist are only called by the Installer target, which is the one that builds the MSI and is normally only called by Visual Studio or an automated build process.  If you put the XmlPreprocess step into a CustomPreRedist target, then it will be complete before any files are copied to the MSI staging folder [$(RedistDir)].

Thanks,
Tom

Feb 28, 2012 at 7:49 PM

Tom,

Fantastic.  This might be a stupid question, but I do not have an MSBuild skill set.  How would I execute the XmlPreprocess from the CustomPreRedist target?  I did it manually and it worked.  I basically want to perform this command on build and before it includes the master bindings in the MSI file:

XmlPreprocess -i BindingsFileListToPreProcess.xml -o PortBindingsMaster.xml

What would I put into Deployment.btdfproj under Target Name="CustomRedist"?  Or is that where that would even go? 

Regards,

Keith

Coordinator
Feb 28, 2012 at 10:48 PM

Hi Keith,

Here's what you need to do.  In your .btdfproj file, after the <Import> element, add this:

<Target Name="CustomPreRedist">
  <Exec Command="&quot;$(DeployTools)\xmlpreprocess.exe&quot; -i BindingsFileListToPreProcess.xml -o PortBindingsMaster.xml" />
</Target>

Since this will create PortBindingsMaster.xml before the copy begins, your new file will end up in the MSI.  If PortBindingsMaster.xml already exists or is marked read-only, you'll need to delete or rename it first.  You can find a reference on the built-in MSBuild 4.0 (assuming BizTalk 2010) tasks here.

Thanks,
Tom

Mar 9, 2012 at 9:00 PM

This worked like a charm.  Thanks Tom.