BizTalk Mapper: Custom Extension XML property fixed with PowerShell script (BizTalk 2010)

Posted: July 30, 2012 in BizTalk
Tags: , , ,

In my last post I explained how to call an external assembly from Custom XSLT in BizTalk Server 2010 using the Custom Extension XML property of the maps.

I also describe that BizTalk Server 2010/Visual Studio 2010 have an issue with this functionality: Visual Studio doesn’t persist the path of Custom Extension XML property in the .BTM file.

As I explained earlier, the workaround that currently exists requires that the user edit manually and .BTM file to add this node between the elements </ScriptTypePrecedence> and <TreeValues>:

<CustomXSLT XsltPath="" ExtObjXmlPath=".\xslt\ExternalAssembly.xml" />

However this is a workaround that can cause many problems, especially maintaining this issue.

It may seem a small issue but imagine you are developing a project that needs this functionality, so you know there is an issue (perhaps after a few hours searching for the solution) and you apply this manual workaround. After solving the problem for the first time you may think that the problem is solved from now on… but is not true!

If for some reason you need to make any changes on the map, when we make a new build to the project you get the message: Build: 1 succeeded or up-to-date, 0 failed, 0 skipped; and if you check the map properties you will see the “Custom Extension XML” property correctly filled… however the compiler will remove this line again, so you need to constantly fix manually the .BTM file.

The only way we can see, through Visual Studio, if the problem is solved or not, is to validate the map:

Validate-Custom-Extension-XML

You will notice that in the Output window will be displayed two links:

  • The first for the output XSLT
  • The second to the Extension Object

If we click in the second, without implementing any workaround, it will show you the following output:

<ExtensionObjects />

And what really was supposed to appear the contents of our ExternalAssembly.xml file:

<?xml version="1.0" encoding="utf-16" ?>
<ExtensionObjects>
  <ExtensionObject Namespace="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" AssemblyName="MapperExtensionsFunctions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cdbffba4cc751306" ClassName="MapperExtensionsFunctions.MappingFunctions" />
</ExtensionObjects>

Now imagine that within five months you need to make a further modification in the map or a new member of the team will take this project to make this change, do you will remember that you need to implement this workaround?

So I spend the last day thinking “outside the box” in order to get a more effective way to solve this problem… and I found it!

Workaround 2 (automatic)

My friend and coworker José Antonio Silva is always trying to convince me to use PowerShell more often in order to automate certain processes and this has made me wonder … maybe it will be a good approach using PowerShell here to solve this problem.

So I created this PowerShell script that associated with the Pre-build actions of Visual Studio project will automatically fix this issue for us:

$xml = New-Object XML
$xml.Load($args[0])

if (!$xml.mapsource.CustomXSLT)
{
	$newelement = $xml.CreateElement('CustomXSLT')
	$newelement.SetAttribute('XsltPath', '')
	$newelement.SetAttribute('ExtObjXmlPath', $args[1])

	$xml.mapsource.InsertAfter($newelement, $xml.mapsource.ScriptTypePrecedence)
	$xml.Save($args[0])
}

Note: the PowerShell script is available for download on the TechNet gallery here.

The script accepts two parameters:

  • The first parameter is the path to the map that we want to configure the custom extension XML;
  • The second is the path to the ExternalAssembly.xml file file that refers the namespace to the FullyQualifiedName (FQN) of the .NET assembly.

Then we need to configure Pre-build actions of Visual Studio project to run this script:

  • Copy the PowerShell script file: ExternalAssembluFix.ps1 to your project directory;
  • Right-click on BizTalk project name and select “Properties” option;
  • On the right three choose “Build Events” option:
    • Select the button “Edit Pre-Build …” and in the “Pre-Build event command line” windows type the following command:
Powershell -File "$(ProjectDir)ExternalAssemblyFix.ps1" "$(ProjectDir)<name_of_the_map>" "$(ProjectDir)ExternalAssembly.xml"
      • Note: you must replace <name_of_the_map> with the name of your map.

Powershell-Pre-Build-event-command-line

Now everytime we made a build to the project, the PowerShell script will check of the element CustomXSLT  is present in the map:

  • If not he will insert automatic this element
  • If the element is present, the script will not do anything.

Therefore we don’t have to worry about maintenance this issue, and in the future when the problem is fixed we also don’t have to worry about removing this workaround, everything will work fine.

PowerShell script from Visual Studio Pre-build event failing

If you try to implement this solution you may get the following error when trying to build the project:

File …\ExternalAssemblyFix.ps1 cannot be loaded because the execution of scripts is disabled on this system. Please see “get-help about_signing” for more details.

But there are no reasons for concern. You just need to learn a few little tricks for running Windows PowerShell scripts.

The Get-ExecutionPolicy cmdlet simply tells you which of the four execution policies (policies that determine which Windows PowerShell scripts, if any, will run on your computer) is currently in-force. The Windows PowerShell execution policies include the following:

  • Restricted – No scripts can be run. Windows PowerShell can be used only in interactive mode.
  • AllSigned – Only scripts signed by a trusted publisher can be run.
  • RemoteSigned – Downloaded scripts must be signed by a trusted publisher before they can be run.
  • Unrestricted – No restrictions; all Windows PowerShell scripts can be run.

So you need to set the execution policy to RemoteSigned:

Set-ExecutionPolicy RemoteSigned

However we must remember that we are using an x64-bit operating system, they have two PowerShell shortcuts:

  • Windows PowerShell(32).lnk (x86): %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
  • Windows PowerShell.lnk (x64): %SystemRoot%\sysWOW64\WindowsPowerShell\v1.0\powershell.exe

And Visual Studio is probably launching the x86 version of PowerShell, so I advise you to set the execution policy in both versions.

I hope you enjoy this solution and perhaps this will help you avoid many problems.
Calling an external assembly from Custom XSLT in BizTalk Server 2010 Maps (65.9 KB)
Microsoft Code Gallery

The sample code in Code Gallery as this workaround implemented.

BizTalk Mapper: Custom Extension XML property fix with PowerShell (BizTalk 2010) (1.0 KB)
Microsoft TechNet Gallery

About these ads
Comments
  1. [...] BizTalk Mapper: Custom Extension XML property fixed with PowerShell script (BizTalk 2010) [...]

  2. Jordan says:

    Sandro, I am not sure if using this method is the reason for my Error. But I am using it successfully in my Development Environment. When I bring over the DLL’s to Sys-Test it seems like the map used for my custom extension isnt being run. Do you have a suggested may for me to verify if my map is being skipped? I dont get an ERROR.

    • Hi Jordan,

      This problem is very strange… unfortunately I can’t replicate your problem but I believe the problem is not due to this workaround… if the map isn’t running maybe is some missing configuration. The map is being invoked through an orchestration or directly from the port?

  3. Jordan says:

    I have never experience something like this. It is being invoked by the Orchestration. I will keep you updated on the Cause and Resolution of this issue.

    • Validate if the external DLL is published in the GAC and maybe you should try to perform Orchestration debug (step by step).

      Open BizTalk Server Administration and make a query in order to find the orchestration that you want, right click and select Orchestration Debugger, set a Breakpoint and send a new message to see what appends.

  4. Jordan says:

    Sandro, TOTALLY unrelated. I modified the expected msg in my DEV environment. In Sys-Test the msg(HL7) was not formed correctly and caused the data I change in my xslt to end up in the Z-Segment of my 3 part message. It seemed like my xslt was being skipped but the data wasnt there for it to process. Thanks for posting this solution on your site. This has been my goto site for months.

  5. Jhalak says:

    I am facing the same issue “Cannot find the script or external object that implements prefix ‘http://schemas.microsoft.com/BizTalk/2003/ScriptNS0′.” in my DEV environment. When I validate the map, the contents of Extension Object as you mentioned in your Workaround 1 solution is already present without adding custom Extension XML or editing the .bmp manually. Still the issue persists. Can you please suggest how to resolve this?

    • Hi Jhalak, You need to manually edit .BTM file to add this node between the elements and and add the following code: or create a powershell like you see in this post to solve this problem. Because each time you change the map the customxslt extension reference is removed.

  6. Jhalak says:

    And this error is only coming while testing the Map. I am able to build the Map successfully.

  7. Jhalak says:

    Do I need to create the ExternalAssembly.xml file again? If yes, where should I save this file? can I reference from any location of my local DEV machine?

    • You need to have a valid ExternalAssembly.xml file referring the correct DLL, you can reference from any location of your local DEV machine but I recommend to put include it in your BizTalk project and on the same location of your project.

  8. Jhalak says:

    And in your code
    which path is “.\xslt\ExternalAssembly.xml”?

    • Hi Jhalak,

      Regarding to you question : “which path is “.\xslt\ExternalAssembly.xml”?”
      In my sample solution, that you can download (see the link in the post) the ExternalAssembly.xml file is in the sample directory of the map, so in this case the path should be “.\ExternalAssembly.xml”

  9. Jhalak says:

    Hi Sandro,
    I tried your workaround solution 1 by referencing the ExternalAssembly.xml file and also I manually edited .btm file.
    Now I am getting the below error:
    The compilation is using the CustomExtensionXml tag (specified in the Grid properties) along with the ExtensionXml that is produced by the map content.
    Item has already been added. Key in dictionary: ‘http://schemas.microsoft.com/BizTalk/2003/ScriptNS0′ Key being added: ‘http://schemas.microsoft.com/BizTalk/2003/ScriptNS0′.

    Can you please tell me how to resolve this?

    • I need to test it but I think you should add the external DLL referenced in the ExternalAssembly.xml to the GAC and then test the map. If you manually add the ExternalAssembly.xml to the map using for example notepad… each time you change something in the map you will need to make this operation again (add the ExternalAssembly.xml reference). Check my sample project.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s