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

Posted: July 30, 2012  |  Categories: BizTalk Visual Studio

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 has 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 edits manually the .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 on 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 to use PowerShell here to solve this problem.

So I created this PowerShell script that associated with the Pre-build actions of the 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 that refers the namespace to the FullyQualifiedName (FQN) of the .NET assembly.

Then we need to configure the Pre-build actions of the 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 the “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 every time we made a build to the project, the PowerShell script will check 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.

Download

You can download BizTalk Mapper: Custom Extension XML property fix with PowerShell (BizTalk 2010) from GitHub here:

You can download Calling an external assembly from Custom XSLT in BizTalk Server Maps from GitHub here:

Author: Sandro Pereira

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community.

23 thoughts on “BizTalk Mapper: Custom Extension XML property fixed with PowerShell script (BizTalk 2010)”

  1. 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.

    1. 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?

  2. 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.

    1. 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.

  3. 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.

  4. 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?

    1. 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.

  5. 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?

    1. 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.

    1. Hi Jhalak,

      Regarding to you question : “which path is “.xsltExternalAssembly.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”

  6. 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?

    1. 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.

  7. Hi Sandro,

    thanks for your post. Made things much clearer. Still having one issue unfortunately.
    same problem as Jhalak.

    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’

    hope you can help.

    Thanks.

    regards,

    Jeroen

  8. Hi Sandro,
    I have used the same map in BizTalk 2010, but same map is not working in BizTalk 2016.
    It is giving the below error, while executing the below code
    public string MapToCanonical(XPathNodeIterator sourceNode)
    {

    XDocument sourceXml = Document.Load(sourceNode.Current.ReadSubtree());
    }
    enumeration-has-not-started-call-movenext

  9. Hi Sandro,

    We are using the same approach of PowerShell script as mentioned by you.It works fine in my local development environment.
    We are using BTDF to create solution build and deploy in other environments.
    When I deploy this in another server using btdf package it doesn’t work and throws the error:
    error:Transformation failed.. —> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.Xml.Xsl.XslTransformException: Cannot find a script or an extension object associated with namespace ‘http://schemas.microsoft.com/BizTalk/2003/ScriptNS7’.
    at System.Xml.Xsl.Runtime.XmlQueryContext.InvokeXsltLateBoundFunction(String name, String namespaceUri, IList`1[] args)

    Can you please suggest?

Leave a Reply

Your email address will not be published. Required fields are marked *

turbo360

Back to Top