Feb 032012
 

Earlier in the week I spent some time trying to accomplish what I thought was going to be a trivial task – mapping from a sequence structure to a flat file structure using BizTalk Development Tools.

The main idea is to take a looping structure on the left hand side and map it to a flat structure on the right hand side.

As it turns out, it’s pretty easy to do, and not complicated.  I spent a lot of time trying to do something more dramatic, if you’re looking for this info, I think you’ll be surprised by how logical the solution is.

Take a schema like the following:

image

Which defines a structure along the lines of this:

<ns0:Account xmlns:ns0="http://Mapping_Project.Inbound">
  <FirstName>Jed</FirstName>
  <LastName>Bartlett</LastName>
  <Address>
    <Line1>1 Constitution Ave</Line1>
    <Line2></Line2>
    <Suburb>Lincoln</Suburb>
    <State>Nebraska</State>
    <Country>USA</Country>
    <PostCode>90210</PostCode>
    <Type>Home</Type>
  </Address>
  <Address>
    <Line1>Suite 10</Line1>
    <Line2>1090 Eggplant Blvd</Line2>
    <Suburb>Washington</Suburb>
    <State>Nebraska</State>
    <Country>USA</Country>
    <PostCode>90211</PostCode>
    <Type>Work</Type>
  </Address>
</ns0:Account>

We’re going to try and transform it into something ugly, like this:

image

Which means flattening the data from the left hand side to the right hand side – but how?

image

First up, generate some test data. It’s a very good habit to get into, and it’s easy as pie. Right click on a schema and select “Generate Instance”. Modify the values so they’re easy to debug with and you’re set.

image

Let’s look at how we transform this simple XML.  The answer, as it turns out is blindingly simple.

Open up your map..

Now, let’s assume we want to apply a condition to how we separate the data on the left hand side.  Let’s assume there will be two types of addresses (Home and Work).  Our aim is to assign all the “Address 1” address details as “Home”, and all the “Address 2” details as “Work”.

Drop two Logical EQUALs functoids onto the map and join them to the “Type” attribute.  Then, open each functoid and we’ll set the comparison value to ‘Home’ and ‘Work’ respectively (omit the quotes).  This applies the logic to split the output.

1. image 2. image

Now, assign all the attributes directly across to their destination.

image

Next, connect each equals functoid to the destination it reflects, i.e. connect the functoid for “Home” to each of the “Address 1” properties, etc.  Don’t forget to map the “Type” too, if you want to capture that detail.

image

Given the data I’ve specified above – let’s give it a test!  With the map open in Visual Studio, open the Properties Window and take a look at the following details:

image

Change the “Test Map Input” to “XML” and then you can specify the path to a test XML document (which you might have created earlier).  Here’s how mine ended up:

image 
image

To test, right click on the map file in Solution Explorer and select “Test Map”.  You should get some results in the output window:

TestMap used the following file: <file:///C:\Dev\BizTalk\Mapping\Mapping Project\Test Data\Inbound_Data.xml> as input to the map.
Test Map success for map file C:\Dev\BizTalk\Mapping\Mapping Project\Maps\InboundToOutbound.btm. The output is stored in the following file: <file:///C:\Dev\BizTalk\Mapping\Mapping Project\Test Output\Output.xml>
Component invocation succeeded.

Which provides a generated instance which looks like this:

<ns0:AccountDetails xmlns:ns0="http://Mapping_Project.Outbound">
  <Name>Jed Bartlett</Name>
  <Address1_Line1>1 Constitution Ave</Address1_Line1>
  <Address1_Line2 />
  <Address1_Suburb>Lincoln</Address1_Suburb>
  <Address1_State>Nebraska</Address1_State>
  <Address1_Country>USA</Address1_Country>
  <Address1_PostCode>90210</Address1_PostCode>
  <Address1_Type>Home</Address1_Type>
  <Address2_Line1>Suite 10</Address2_Line1>
  <Address2_Line2>1090 Eggplant Blvd</Address2_Line2>
  <Address2_Suburb>Washington</Address2_Suburb>
  <Address2_State>Nebraska</Address2_State>
  <Address2_Country>USA</Address2_Country>
  <Address2_PostCode>90211</Address2_PostCode>
  <Address2_Type>Work</Address2_Type>
</ns0:AccountDetails>

There were some warnings about multiple mappings, but I didn’t find the absence of a looping functoid to be a problem.  I realise this is a pretty obvious and simple mapping, but when I went looking for examples about how to solve this type of mapping, I couldn’t find much at all (including from e-books).

There’ll be more on BizTalk mapping and other fun stuff in some upcoming articles.

Jan 062012
 

Introduction

From time to time, it is natural for us to deploy BizTalk solutions with Assembly dependencies.  Usually this is because we have created helper classes (for mapping, or querying) or perhaps it reuses some common logic shared between application suites.

Whatever the reason, it can be very handy to pick up all assemblies when we export the BizTalk Application from BizTalk Administration, when we use the Export MSI feature/wizard.

The Problem

The one drawback is that, since BizTalk requires assemblies to be GAC’d (that is, strong named and added to the Global Assembly Cache), it’s hard for a tool, like the export to MSI wizard, to know what are custom assemblies which the BizTalk assemblies rely on (that aren’t system or framework assemblies).

In other words, you need a way to call out the dependencies, so that the export wizard will package the entire application.  The alternative would be that you would have to ensure any custom dependencies are already deployed to your (new) target environment.

The Solution

As you might be aware, you can view a BizTalk application’s resources (assemblies) from within BizTalk Administrator.  What you may not know is that you can add “Resources” to this location.  In particular, you can add (or call out) dependency assemblies.

Just right click in the Resources view, and select Add->Resources..

image

A dialog pops up and allows you to browse for the required assemblie(s).  You have some options here, you can force the assemblies to overwrite, you can select if and when the chosen assemblie(s) are GAC’d (registered with the GAC), registered as COM components or made visible to COM components.

image

The dependencies tab allows you to quickly see if all the dependencies for a specific assembly are to be found.  This will help you check and ensure your solution has everything it needs.

When you decide to do an “Export to MSI”, you’ll notice that it now includes any dependency resource Assemblies which you have added to your application:

image

If the assembly you are adding has a dependency on another assembly that is not included in the application, the add operation will fail.

Great, but what if I want to automate this procedure as part of an automated deployment?

I’m glad you asked.  Naturally, you can script commands which will accomplish this task for you.  You could easily script this command, to be included in automated builds or deployments.

Note that, as a general rule, it is not advised to automatically register any assemblies in the Global Assembly Cache of a build machine/build server.

Steps to add assemblies from command line:

  1. Open a command prompt as follows: Click Start, click Run, type cmd, and then click OK.

    Note: you may require elevated permissions to accomplish this, you’ll certainly need permissions to administer BizTalk Server as well.
     

  2. Type the following command, substituting the appropriate values, as described in the following table.

Command Syntax:

BTSTask AddResource [/ApplicationName:value] /Type:System.BizTalk:BizTalkAssembly [/Overwrite] /Source:value [/Destination:value] [/Options:GacOnAdd|GacOnInstall|GacOnImport] [/Server:value] [/Database:value]

Example:

BTSTask AddResource /ApplicationName:MyApplication
/Type:System.BizTalk:BizTalkAssembly /Overwrite
/Source:"C:\BizTalk Assemblies\MyOrchestration.dll"
/Destination:"C:\New BizTalk Assemblies\
MyOrchestration.dll " /Server:MyDatabaseServer
/Database:BizTalkMgmtDb

The following is a complete list of options lifted from MSDN, but they approximate what you can do via the BizTalk Administrator console.

Parameter Value

/ApplicationName

Name of the BizTalk application to which to add the BizTalk assembly. If the application name is not specified, the default BizTalk application is used. If the name includes spaces, you must enclose it in double quotation marks (").

/Type

System.BizTalk:BizTalkAssembly

/Overwrite

Option to update an existing assembly. If not specified, and an assembly already exists in the application that has the same LUID as the assembly being added, the AddResource operation fails. You can view the LUIDs for the artifacts in an application by using the ListApp Command. If another application depends on the assembly being overwritten, the AddResource operation fails, even when this parameter is specified.

/Source

Full path of the assembly file, including the file name. If the path includes spaces, you must enclose it in double quotation marks (").

/Destination

Full path of the location where the assembly file is to be copied when the application is installed from the .msi file. If not provided, the assembly file is not copied to the local file system during installation. If the path includes spaces, you must enclose it in double quotation marks (").

/Options

  • GacOnAdd: Specify to install the assembly to the global assembly cache (GAC) on the local computer during the AddResource operation.
  • GacOnInstall: Specify to install the assembly to the GAC when the application is installed from the .msi file.
  • GacOnImport: Specify to install the assembly to the GAC when the application .msi file is imported.

You must separate multiple options with a comma.

/Server

Name of the SQL Server instance hosting the BizTalk Management database, in the form ServerName\InstanceName,Port.

Instance name is only required when the instance name is different than the server name. Port is only required when SQL Server uses a port number other than the default (1433).

Examples:
Server=MyServer
Server=MyServer\MySQLServer,1533

If not provided, the name of the SQL Server instance running on the local computer is used.

/Database

Name of the BizTalk Management database. If not specified, the BizTalk Management database running in the local instance of SQL Server is used.

Further Reading

How to Add a BizTalk Assembly to an Application
http://msdn.microsoft.com/en-us/library/aa558703%28BTS.20%29.aspx

More on BizTalk Deployments
http://social.msdn.microsoft.com/Forums/en-US/biztalkgeneral/thread/1e6cd3a9-42d1-42b8-911c-c3f7bdc35145/