Maps mit Referenzen zu externen Assemblies debuggen

Um BizTalk-Maps zu debuggen, die eine exterene Assembly aufrufen, reichen die Standard-Möglichkeiten nicht mehr aus. Es erscheint die Fehlermeldung

Cannot find the script or external object that implements prefix ‘http://schemas.microsoft.com/BizTalk/2003/ScriptNS0’

Um das zu umgehen, müssen die externen Assemblies dem Debugger bekannt gemacht werden. Um allgemein XSLT zu debuggen kann, neben der Möglichkeit dies über das Menü XMLDebug XSLT zu erledigen, auch das Objekt XslCompiledTransform verwendet werden. Hierdurch ist man wesentlich flexibler und kann z.B. StartParameter angeben und/oder eben Extension Objects. Und da eine BizTalk-Map letztendlich auch nur ein XSLT-Dokument darstellt, gilt das auch dafür.

Als erstes sollte man ein C#-Projekt zur BizTalk-Solution hinzufügen. Darin wird lediglich unten stehende Methode eingefügt und die Main-Methode so angepasst, dass ein Aufruf der Methode DebugXslt mit den jeweiligen Parametern erfolgt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/// <summary>
/// Helper Method to debug Maps with Extension Objects
/// </summary>
/// <param name="mapXslt">Path to xslt-file generated by the MapperCompiler (Validate Map)</param>
/// <param name="inputXml">Path to input-file (Test Map)</param>
/// <param name="extensionObjectsXml">Path to Extension Object XML (Validate Map)</param>
static void DebugXslt(string mapXslt, string inputXml, string extensionObjectsXml) {
if (!string.IsNullOrEmpty(mapXslt) && !string.IsNullOrEmpty(inputXml) && File.Exists(mapXslt) && File.Exists(inputXml)) {
XslCompiledTransform xslt = new XslCompiledTransform(true);
// allow embedded scripts and document()-function
XsltSettings xsltSettings = new XsltSettings(true, true);
// Load the style sheet.
xslt.Load(mapXslt, xsltSettings, null);
// resolve extension objects
XsltArgumentList xsltArgs = new XsltArgumentList();
if (!string.IsNullOrEmpty(extensionObjectsXml) && File.Exists(extensionObjectsXml)) {
XmlReaderSettings rsettings = new XmlReaderSettings();
rsettings.IgnoreComments = true;
rsettings.IgnoreProcessingInstructions = true;
rsettings.IgnoreWhitespace = true;
using (XmlReader reader = XmlReader.Create(extensionObjectsXml, rsettings)) {
reader.ReadStartElement("ExtensionObjects");
do {
string ns = "", an = "", cn = "";
while (reader.MoveToNextAttribute()) {
switch (reader.LocalName) {
case "Namespace":
reader.ReadAttributeValue();
ns = reader.Value;
break;
case "AssemblyName":
reader.ReadAttributeValue();
an = reader.Value;
break;
case "ClassName":
reader.ReadAttributeValue();
cn = reader.Value;
break;
}
}
// load type and add instance to xslt-Arguments
if (!string.IsNullOrEmpty(ns) && !string.IsNullOrEmpty(an) && !string.IsNullOrEmpty(cn)) {
Type t = Type.GetType(Assembly.CreateQualifiedName(an, cn));
xsltArgs.AddExtensionObject(ns, System.Activator.CreateInstance(t, false));
}
} while (reader.ReadToNextSibling("ExtensionObject"));
reader.Close();
}
}
// Execute the transformation.
using (XmlWriter writer = XmlWriter.Create(TextWriter.Null)) {
xslt.Transform(inputXml, xsltArgs, writer);
writer.Close();
}
xsltArgs.Clear();
}
}
ParameterBeschreibung
mapXsltPfad zur XSLT-Datei
inputXMLPfad zur der Datei, die die Testdaten enthält
extensionObjectsXmlPfad zur Datei, in der die Erweiterungsobjekte stehen (darf leer sein)

Nun müssen noch die einzelnen Pfade ermittelt werden. Mittels Validate Map (rot im Bild) werden die XSLT-Datei und die extensionObjects-Datei erstellt. Im Output-Window erscheinen die jeweiligen Pfade und müssen nur noch übernommen werden.
Hat man kein XML-Dokument, mit dem man Testen kann, sondern ein natives Format, so hilft Test Map. Auch hier erscheint im Output-Window der Pfad mit dem Hinweis Test Map used the following file.

Sind nun alle 3 Pfade ermittelt und eingetragen, kann es auch endlich losgehen. Damit der Debugger nicht einfach durchläuft, sollte die XSLT-Datei geöffnet und eine Haltepunkt eingefügt werden.

Nun muss das Projekt gestartet werden. Dazu mit der rechten Maustaste auf das Projekt zeigen und DebugStart new instance ausführen.
Alternativ das Projekt als StartUp-Project einrichten und F5 drücken…