I had a case today where I was mapping two fields N01 and N02 to two side by side fields in the output schema.

N01 was working, and N02 wasn’t.  Both were under an condition that a certain variable MESSAGE_TYPE was equal to a certain value.  Yet one worked, the other didn’t?   How did I go about debugging this?

I did a right click “Validate Map”, and opened the XSLT.  I searched for N01, and found the following.

XSLT_Debug_Sample_1

Can you spot any clues to the issue?  If not scroll on down…

 

 

 

 

 

 

 

 

 

 

 

 

 

In the image below, I have highlighted some of the code. The N01 is wrapped by one IF statement, so I would expect the same IF statement around N02.

But when I look at N02, I see to nested IF statements.

XSLT_Debug_Sample_2

You can find the variables to understand what the tests are.  So I searched for the extra test around N02, i.e. the variable v16, and found this.

XSLT_Debug_Sample_3

That jogged my memory.  I had another page on the map, where we were using a “trick” to not map certain fields.
This was a RosettaNet schema, and it contained many nodes with default values that were filling up the output document with unnecessary junk. The “trick” is to map “false” to the fields you don’t want to map.  So I had essentially told the map that I did not want to output this element (even though I had mapped something to it).

Of course, this is only one small case, but I hope you like the methodology, and can use it to apply to your own debugging.  Learning XSLT of course helps.  The XSLT generated by BizTalk can be a little confusing because of all the “userCSharp” routines, and all the variables, but it can help you find issues in your map while testing.

Also note, I would not have found this issue unless I was carefully unit-testing.  I hand-crafted 5 different input test files, and was running each one of them through the “Test Map” feature, and manually scanning the output.

 

In the past, I admit, I was a GAC’cer.  Yes, that means that I would run GACUTIL to deploy minor code changes to BizTalk Ochestrations.

Where I currently work, that is not the best practice for several reasons.  One reason is that if you  create an MSI after doing the GAC, the MSI will not contain the newest DLL.  At other places I worked, this was not an issue, because we used the BizTalk Deployment Framework (BTDF).

Last week, I had an orchestration that was rather difficult to test in my own environment.  So I wanted to compile it, deploy the .DLL to our QA environment, and test it there.  But I had to do this over-and-over, making minor little changes.

The manual process was:

  1. Stop the orchestration (and make sure to terminate any suspended instances).
  2. Go to the “Add Resource”, click a button to find the .DLL, wait a few seconds, then click a few check boxes, and click the “OK” button, and wait a few more seconds.
  3. Since we had two machines in our QA environment, I had to repeat Step 2 on the second machine.
  4. Then start the orchestration
  5. Then restart the host instances (so the new code would be picked up)

I vaguely remember the BTSTASK command, but haven’t used it for years outside of BTDF, so I looked it up, and created the following .cmd file:

cscript "c:\Program Files (x86)\Microsoft BizTalk Server 2010\SDK\Samples\Admin\WMI\Stop Orchestration\VBScript\StopOrch.vbs" "MyProjNamespace.MyOrchName" "MyAppName" Unenlist
"c:\Program Files (x86)\Microsoft BizTalk Server 2010\BTSTask.exe" AddResource /ApplicationName:MyAppName /Type:System.BizTalk:BizTalkAssembly /Overwrite /Source:MyProjNamespace.dll /Options:GacOnAdd,GacOnInstall,GacOnImport >ReplaceResources_Log.txt
cscript "VBScript\StartOrch.vbs" "MyProjNamespace.MyOrchName" "MyAppName"

The program called StopOrch.vbs existed in the BizTalk provided SDK/examples. However, there was no StartOrch.vbs, so I had to create the VBScript to start an orchestration (see link to separate blog on that).  Heres the MSDN Doc for BTSTask with the AddResource parameter.

I’m still doing Step 5 manually.  I copy the .DLL to server1 and server 2 in the BizTalk group.  I then run the above script on each server.  Then I restart the host instances manually.

This blog contains a sample VBScript to start a BizTalk Orchestration

The SDK (Software Development Kit) of BizTalk includes a sample to stop orchestrations.
“c:\Program Files (x86)\Microsoft BizTalk Server 2010\SDK\Samples\Admin\WMI\Stop Orchestration\VBScript\StopOrch.vbs”
I guess, since it is just a sample, they chose not to provide the opposite to “Start” orchestrations.

I was having to deploy just a .DLL, not entire MSI over and over, so I started to make a script to do it. I need to stop the orchestration, run BTSTask with the AddResource option, then start the orchestration.

The trick is that you have to Enlist it before Starting it. So I run both the .Enlist and the .Start methods, one right after the other. I removed the optional UNENLIST parm.

Below is the VBScript:

'--------------------------------------------------------------------------
'
' ScriptName: StartOrch.vbs 
' WMI script to start a specific orchestration.
' Neal Walters - 02/10/2016 took StopOrch.vbs in BizTalk SDK to make StartOrch.vbs 
'
'--------------------------------------------------------------------------
' This file is based on samples in the Microsoft BizTalk Server 2009 SDK
'--------------------------------------------------------------------------

Option Explicit

StartOrch
Sub StartOrch()
	'Get the command line arguments entered for the script
	Dim objArgs: Set objArgs = WScript.Arguments

	'error handling is done by explicity checking the err object rather than using
	'the VB ON ERROR construct, so set to resume next on error.
	on error resume next
	
	'Make sure the expected number of arguments were provided on the command line.
	'if not, print usage text and exit.
	If (objArgs.Count <> 2) Then
		PrintUsage()
		wscript.quit 0
	End If

	Dim InstSet, Inst, Query, OrchestrationName, AssemblyName, Unenlist
	Dim AutoDisableReceiveLocation: AutoDisableReceiveLocation = 2
	Dim AutoSuspendOrchestrationInstance: AutoSuspendOrchestrationInstance = 2
	
	OrchestrationName = objArgs(0)
	AssemblyName = objArgs(1)
			
	'set up a WMI query to acquire a list of orchestrations with the given Name and 
	'AssemblyName key values.  This should be a list of zero or one Orchestrations.
	WScript.Echo "Orch=" & OrchestrationName
	WScript.Echo "AssemblyName=" & AssemblyName 
 	Query = "SELECT * FROM MSBTS_Orchestration WHERE Name =""" & OrchestrationName & """ AND AssemblyName = """ & AssemblyName & """"
	WScript.Echo "Query=" & Query 
	Set InstSet = GetObject("Winmgmts:!root\MicrosoftBizTalkServer").ExecQuery(Query)
	
	'Check for error condition before continuing.
	If Err <> 0	Then
		PrintWMIErrorThenExit Err.Description, Err.Number
	End If

	'If orchestration found, enlist the orchestration, otherwise print error and end.
	If InstSet.Count > 0 then
		For Each Inst in InstSet
		    Inst.Enlist
			If Err <> 0	Then
				PrintWMIErrorThenExit Err.Description, Err.Number
			End If
			Inst.Start 
			If Err <> 0	Then
				PrintWMIErrorThenExit Err.Description, Err.Number
			End If
			wscript.echo "The Orchestration was successfully started."
			
		Next
	Else
		wscript.echo "No orchestration was found matching that Name and AssemblyName. InstSet.Count=0"
	End If
			
End Sub 

'This subroutine deals with all errors using the WbemScripting object.  Error descriptions
'are returned to the user by printing to the console.
Sub	PrintWMIErrorThenExit(strErrDesc, ErrNum)
	On Error Resume	Next
	Dim	objWMIError	: Set objWMIError =	CreateObject("WbemScripting.SwbemLastError")

	If ( TypeName(objWMIError) = "Empty" ) Then
		wscript.echo strErrDesc & " (HRESULT: "	& Hex(ErrNum) & ")."
	Else
		wscript.echo objWMIError.Description & "(HRESULT: "	& Hex(ErrNum) & ")."
		Set objWMIError	= nothing
	End	If
	
	'bail out
	wscript.quit 0
End Sub 

Sub PrintUsage()
	WScript.Echo "Usage:" + Chr(10) + Chr(10) + _
		     "cscript StartOrch.vbs <Orchestration Name> <Assembly Name>" + _	
		     Chr(10) + Chr(10) + "Where: " + Chr(10) + _
		     "<Orchestration Name> = The name of the orchestration you wish to enlist." + _
		     Chr(10) + "       Example: 'MyBusinessOrchestration'" + Chr(10) + Chr(10) + _
		     "<Assembly Name>      = The name of the assembly in which the orchestration was deployed." + _
		     Chr(10) + "       Example: 'MyBusinessAssembly'" + Chr(10) + Chr(10) + _
		     Chr(10) + "       Example: 'Unenlist'" + Chr(10) + Chr(10)
End Sub

To run it:
cscript “VBScript\StartOrch.vbs” “ProjNamespace.OrchName” “AppName”

Today, I was tasked with upgrading an orchestration from calling one version of a web service (version 3), to a newer version 4.

Fortunately, it was backward compatible, i.e. I didn’t have to remap any fields. However, the schema was renamed, as it actually had the version number in the web service name. So how does one do this in BizTalk?

In this case, I’m sure there are many paths to the same destination, but here are the steps I followed.

1. I opened a new temporary Visual Studio BizTalk project and consumed the new web service (using the “Add Generated Items” / “Consume WCF Service”). The reason I did it in a separate new project is that it creates the dummy orchestration, and the binding files.

2. I then copied the 2 or 3 schema files to my actual project.

3. I checked my map out (from source control), and opened it in NotePad++ and had to do one small surgery. I had to find Reference Location=”..\WebServices\PlaceOrder_V3.xsd” and replace it with “..\WebServices\PlaceOrder_V4.xsd”. I could have tried it in map, but I’ve seen too many cases where you lose all your mappings, so I did it this way. I then opened the map to verify, and all looked good there.

I then removed the old web service schema, and did a Rebuild, just to see what would happen, which lead to the next two steps.

4. I had to reassociate my Multi-part Message types. Since the messages were using multi-part message types, they were okay as is. But I had two messages types (one for the web service request, and one for the response) that were “red” and had to change. So I just had to carefully pick the new .xsd name for each. (Could have done this also by editing the .odx file, if done carefully.)

5. If you had promoted (or distinguished fields) on the web service schema, you would have to redo those, and that was the case in this orchestration. Then, a really weird scenario happened. Every expression shape that was using the distinguished fields was getting an error. There was not red squiggly line under the items, just a compile error. Even closing and reopening Visual Studio did not solve it.

In one case, I re-typed the msg.property_name using Intellisense, and that solved the issue. For another shape, I did the same thing and it wouldn’t go away. I took a wild stab at it, and created a new expression shape, cut and pasted the statements from the old shape to the new shape, then it compiled clean. I cannot explain that part at all!

6. I’m about to change the URL in the SendPort now, and start testing. I’ll update if anything else unusual happens. I did not use the binding files created by the “Add Generated Items” in the first step above.

6a. Things went bad during testing, took me way too long, like 2 hours to get it working. I had to deploy to QA environment, because it was easier to test.
6b. One issue I had forgot was that the SOAP Action Headers needed to change (in the General configuration tab of the SendPort), for example:
<Operation Name=”PlaceOrder” Action=”http://mysite.com/webservices/neworder_v3/2013/01/PlaceOrder” />
<Operation Name=”PlaceOrder” Action=”http://mysite.com/webservices/neworder_v4/2015/11/INewOrder/PlaceOrder” />

6c. For some reason, it still didn’t work. I’m checking with the authors of the webservice if they change anything else. To finally get it to work, I had to take the CustomBindings.xml file, and run it on the QA system, then change my orchestration bindings to use the new SendPort.