a trace of thought on...BizTalk Server, Team Foundation Server, Windows Mobile, etc. RSS 2.0
 Tuesday, June 27, 2006

Update: Andy pointed out that Tom Abraham has given this a thorough treatment here.

There appear to be cases where having BizTalk 2004 and the .NET 2.0 framework installed on the same machine may cause you some difficulty.  I've seen a few instances where the BizTalk service will not start...or where the BizTalk 2004 process is loading (gulp) the 2.0 runtime (so says Process Explorer.)  This latter behavior will result in the VS2003 debugger not attaching correctly (among other things...)  See this kb.

To fix this, you can modify the BTSNTSvc.exe.config file to include the following (after 'configSections'):          

<startup>
<supportedRuntime version="v1.1.4322"/>
</startup>
Tuesday, June 27, 2006 9:45:36 AM (Central Standard Time, UTC-06:00)  #    Comments [1] -
BizTalk Insights
 Friday, June 23, 2006

In my last post I indicated there was a better story in BizTalk 2006 for working with the C# code that is generated as an intermediate when compiling ODX (orchestration) files - that is, better than having to deal with temporary files and the BizTalk 2004 File Dump utility.  I

If you've worked with BizTalk 2006, you might have already stumbled across this.  The xlang compiler for BizTalk 2006 is kind enough to place the intermediate C# file for your ODX directly in the project directory.  If you have multiple orchestrations in an assembly, you will find a C# file for each orchestration - but only one of those files will actually have content (all the generated C# code is consolidated into one file.)

What this means is that you can do symblic debugging of orchestrations in a fashion far easier than what I described for BizTalk 2004.  The Edit/Debug cycle might look like this:

  1. Build your orchestration project.
  2. Open the associated (generated) C# file - perhaps make it a solution item for convenience.
  3. Search for something in one of your expression shapes (say "MyClass.Execute"), and set a breakpoint.
  4. From the Debug menu, choose Processes and attach to BTSNTSvc.exe. (Have more than one?) Choose CLR debugging only - not native. The symbols should be loaded automatically - no need to copy PDBs to the GAC for this case.
  5. Trigger your orchestration however you normally would.
  6. Find your problem, Debug-Detach All, and fix the problem in the orchestration.
  7. Decide that you really want Gilles' MessageContext Debugger Visualizer

There is another benefit to having the generated C# files for orchestrations be more accessible...If you deploy your PDBs to the GAC, either using either my upcoming deployment work for BizTalk 2006 or just the GetGacPath2 utility that I made available here, you will find that stack traces that are recorded in the event log actually reference line numbers within the generated C# code.

As I said in an earlier post, if you are responsible for troubleshooting BizTalk applications in production, you are likely hungry for all the information you can get about why something is failing.  Since all BizTalk project assemblies are in the GAC, the stack traces you get (either from your own logging, or the event logs BizTalk generates for unhandled exceptions) do not contain file and line number information by default.  This makes post-mortem analysis a lot harder...

When a BizTalk 2006 application is deployed to production, you might consider archiving the generated C# code for production support.  If you use GetGacPath2 to put PDBs in the GAC, you will have file and line number information within captured stack traces to aid in troubleshooting. (Note that GetGacPath2 supports MSIL, 32 bit, and 64 bit assembly caches.  MSIL is the right choice for BizTalk 2006 projects.)

Friday, June 23, 2006 11:20:03 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
BizTalk Insights
 Wednesday, March 01, 2006

In the last release of the BizTalk Deployment Framework, an additional feature was added that I thought deserved its own post for explanation...

If you are responsible for troubleshooting BizTalk applications in production, you are likely hungry for all the information you can get about why something is failing.  Since all BizTalk project assemblies are in the GAC, the stack traces you get (either from your own logging, or the event logs BizTalk generates for unhandled exceptions) do not contain file and line number information.  This makes post-mortem analysis a lot harder...

A new custom NAnt task (getgacpath) and corresponding support within BizTalkDeploymentInclude.nant was added for placing PDB (program database) files for all BizTalk and component assemblies into the GAC.  (You can use just this NAnt task without the rest of the Deployment Framework, of course.  In addition, a standalone command line utility called GetGacPath has been included in the "Tools" download.)

Why is this interesting?  Well, because it allows you to get stack traces that include file and line number information even when assemblies reside in the GAC.  (This is obviously useful and useable outside the domain of BizTalk...)  Without extra work, file and line number information is generally missing from a stack trace if a PDB file is not co-located physically with the corresponding assembly.  Putting the PDB file directly into the GAC is an easy way of solving this problem.

Set the "deployPDBsToGac" NAnt property to "true" in your project-specific NAnt file to get this functionality.

A couple of points are worth mentioning:

  • If the directory structure of the GAC were to ever change, this would need to be updated.  (See my upcoming post on using this technique with .NET 2.0.)
  • It would be great if Gacutil.exe provided this functionaity, but it doesn't. 
  • You should strongly consider having your release-mode binaries (aka 'deployment' configuration in BizTalk) build PDB files - there is no reason not to.  Look under Project properties/Configuration properties/Build/Generate Debugging Information.
  • Stack traces that show up in the event log either through your own logging, or via BizTalk (because the exception was unhandled) will now have file and line number info.  For orchestrations, the file name will correspond to the temporary C# file generated at compile time.  If you use the techniques described in this post , you can correlate back to the actual statement that failed.  For instance, the event log might say:
    [4740] ERROR BizTalkSample.Orchestrations.TopLevelOrch - An exception was caught. 
    [a08701ff-bf80-4940-9f9f-c2bb8597684b]
    System.Exception: Something exceptional happened.
       at BizTalkSample.Orchestrations.TopLevelOrch.segment2(StopConditions stopOn) in 
       c:\Documents and Settings\Scott\Local Settings\Temp\h0li3wbi.0.cs:line 2538
    
  • If you grab the file mentioned (h0li3wbi.0.cs) using BTSFileDump (again,see here) you can cross-reference this message to a location in the generated C# code for TopLevelOrch:

    You might save off "h0li3wbi.0.cs" (the temp file name chosen when TopLevelOrch compiled) and the other generated files when you do your build, using BTSFileDump. (That would be tough to do if you build with CruiseControl, etc.) But you wouldn't have to do that - if you can retrieve the source code used for a particular deployment, then the line number alone should be sufficient to get you to the exception site (since you can find the correct temp file by looking for comments, etc. that are in the orchestration - just like if you were using this technique to do live debugging.)  This all gets better with BizTalk 2006 - see a future post on this topic. 
  • Final point: If you set deployPDBsToGac to "true", deployments will begin by stopping the BizTalk services (instead of just bouncing the services at the end.)  The reason for this is that the BTSNTSvc.exe process will not "let go" of an assembly for which it has loaded a PDB file (so you have to terminate it.)  This means you may not always want this switch on for the developer edit/run/debug cycle.
Wednesday, March 01, 2006 12:43:19 PM (Central Standard Time, UTC-06:00)  #    Comments [1] -
Deployment Framework

There are some updates to the Deployment Framework and log4net story that I've been meaning to release for quite some time. After this, I'll focus my deployment efforts on BizTalk 2006 (didn't I say that last release?)

Below are a list of revisions. On this blog's home page under "Downloads", you will find an updated full download (with sample), as well as updated "Core" and "Tools" downloads.  "Core" contains only the deployment framework itself and can be used for upgrades of existing projects.  "Tools" contains source for all utilities used by the framework.  Be sure to put a fresh copy of BizTalk.NAnt.Tasks.dll in your nant\bin directory. 

  • Update to the log4net.Ext.Serializable library.  Note that the "Tools" download now has variants of this library for both log4net 1.2.0 and 1.2.9, though the sample is built against 1.2.9.  The important change here is that the original version of the library had a threading bug...as a result, the usage pattern for the library has changed somewhat.  Now, an instance of log4net.helpers.PropertiesCollectionEx is declared (as an orchestration variable), and an expression shape at the top of your orchestration will do something like below (notice logProps is passed to all logging calls so as to preserve context despite thread changes across dehydrations.)  See the sample for additional detail.

    logger = log4net.Ext.Serializable.SLogManager.
       GetLogger(@"BizTalkSample",log4net.helpers.CallersTypeName.Name);
    ...
    logProps.Set("InstanceId",TopLevelOrch(Microsoft.XLANGs.BaseTypes.InstanceId));
    logger.Debug(logProps,"Received top level request...");               
                   
  • Update to the SSOSettingsFileReader class to include an "Update" method.  Likewise, an additional custom NAnt task called "updatessoconfigitem" that allows you to add or update config items within an SSO affiliate application.  What is the use case for this?  Suppose you have a piece of information that you a) don't want to store in SettingsFileGenerator.xls (perhaps because you can't manage that file securely) and b) you need access to at run time.  (For instance, it might be an Oracle username/password.)  You could ask an operator/admin for this information at deployment time using SetEnvUI.exe/InstallWizard.xml (from the deployment framework) -- and then in your project-specific NAnt file do this:

       <target name="customSSO" if="${property::exists('serverDeploy') and serverDeploy}">
          <updatessoconfigitem ssoitemname="databaseUserName" ssoitemvalue="${sys.env.databaseUserName}"/>
          <updatessoconfigitem ssoitemname="databasePassword" ssoitemvalue="${sys.env.databasePassword}"/>
       </target>            
          

    At runtime, you can simply use SSOSettingsFileReader to retrieve this information.  Note that this example checks for whether we are doing a server deployment - so in this case, we would have the development environment values in SettingsFileGenerator.xls. 

  • Added a small utility called SSONameValueDump to the tools download to view current name/value pairs of an SSO affiliate application (if you have appropriate permissions.)
  • Update to the <controlbiztalkports> custom NAnt task to allow Send Port Groups to be shared across projects.  That is, Send Port Groups will only be removed if they no longer contain Send Ports (and putting new Send Ports into an already-existing Send Port Group will happen automatically.)
  • XmlPreprocess will be run against log4net configuration files, if you are using log4net. This allows you to use SettingsFileGenerator.xls to control logging levels for different physical environments.
  • SetEnvUI.exe no longer defaults to "last directory" when doing a file browse, to avoid confusion between applications when managing multiple BizTalk application installs.
  • If you use ElementTunnel, you will find that the xpath file will be reversed automatically for unescape operations (thanks to Frank de Groot for that update!)
  • Fix: When deploying HTTP/SOAP infrastructure, file system permissions granted to the specified application pool account.
  • Fix: The "quick update" target (updateOrchestrations) now respects true/false properties for includeSchemas, includeTransforms, etc. (A menu option in Visual Studio is created for this target when you use the MakeBizTalkExternalTools script. The target updates orchestrations, components, schemas, and transforms (see Flanders' post on this) Using this as part of your normal edit/run/debug cycle is a must for productivity…)
  • Fix: Handle multiple assemblies (of one artifact type) correctly in more cases, including where we are not deploying to the management database (i.e. gac deployment only.)

Download: Full Sample, Framework Core, Tools Source

Wednesday, March 01, 2006 12:27:09 PM (Central Standard Time, UTC-06:00)  #    Comments [10] -
Deployment Framework
 Thursday, January 19, 2006

Late notice, I know, but if you can...be sure to join us at 6:00 pm at the local Microsoft office in Bloomington!

Jim Gaudette will be discussing reusability in BizTalk, and hey, food and beverages provided.

Thursday, January 19, 2006 11:43:41 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
General
 Monday, January 02, 2006

I've noticed that - despite a fair bit of discussion on the topic - many folks wind up using atomic scopes simply to avoid serialization requirements for .Net types within an orchestration.  It isn't surprising this is the past of least resistance - after all, the relevant compiler error sort of suggests this as a fix:

error X2141: a non-serializable object type 'SomeAssembly.SomeComponent yourComponent' can only be declared within an atomic scope or service

Recall that persistence will occur when messages are sent, when another orchestration is started asynchronously (like via the Start Orchestration shape), when an orchestration instance is suspended, when a host instance does a controlled shutdown, when a "wait" state occurs (like a blocking receive or delay shape that makes the schedule a candidate for dehydration), or when the orchestration completes. 

It will also occur at the end of a transactional scope to assist with resuming in an unambiguous state (and executing compensation logic.)

So...although the introduction of an atomic scope prevents serialization within the scope, it introduces serialization at the end of the scope.  This is often a persistence point (read: database hit) you wouldn't have had to live with -- if an atomic scope was introduced purely to get around the compiler error above.

Now...sometimes the .Net component you are using indeed requires state - and you should go ahead and implement a serialization strategy for that case.  If the component can be stateless, then you might consider making the methods you access "static" to avoid the compiler-enforced requirement altogether.

There is a third case, however - where you know that serialization is not required (given how your orchestration is structured) - but you don't own the code for it, either.  For instance, you might want to use an XmlNode to hold the result of a SelectSingleNode call on an XmlDocument.  If your use of the XmlNode instance is confined to a single expression shape...no state actually needs to be preserved.  So, in this case, consider wrapping the class as shown below.  Here, we honor the serialization requirement - but we don't, in fact, do any serialization work.  Now, no atomic scope is needed (avoiding the associated performance hit).  Use this technique with care - the state management facilities in BizTalk are usually a great asset.

      
/// <summary>
/// It can be helpful when dealing with xpath expressions within orchestrations to
/// make use of a System.Xml.XmlNode (or derivations) without having to deal 
/// with the fact that XmlNode is not serializable.  If usage is confined to a single
/// expression shape, we actually won't have any serialization requirements, and so they
/// have empty implementation here.
/// </summary>
[Serializable]
public class BizTalkXmlNode : ISerializable
{
	private XmlNode _xmlNode;

	public BizTalkXmlNode()
	{

	}

	public XmlNode XmlNode
	{
		get{return _xmlNode;}
		set{_xmlNode = value;}
	}

	public string InnerText
	{
		get{return _xmlNode.InnerText;}
		set{_xmlNode.InnerText = value;}
	}

	// This is helpful to use as a static helper method because the xpath expression in 
	// biztalk returns a XmlNode - so direct comparisons to string literals won't work.
	// (And the expression editor won't let you get the InnerText property...)
	public static string GetInnerText(XmlNode node)
	{
		return node.InnerText;
	}

	private BizTalkXmlNode(SerializationInfo info, StreamingContext context)
	{
		// no state intended...
	}

	public void GetObjectData(SerializationInfo info, StreamingContext context)
	{
		// no state intended...
	}

} 
    
Monday, January 02, 2006 3:24:57 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
BizTalk Insights
 Monday, November 21, 2005

I had a chance to speak at the Twin Cities BizTalk User Group last Thursday.  It was a great turnout, entirely too much pizza, and a lot of fun to talk to folks throughout the area about how they are using BizTalk.  The deployment talk had 2004 content and a bit on 2006 as well – slides are here.

Monday, November 21, 2005 9:55:26 AM (Central Standard Time, UTC-06:00)  #    Comments [5] -
Deployment Framework
 Friday, November 04, 2005

This great post from Tomas on receiving ack/nack notifications from the MSMQ[C] adapter prompted me to write up something I had researched a few weeks back...

But first, a bit of background...

When doing work with message queueing systems, a very common (and well supported) convention exists when two systems are exchanging messages: System 'A' sends a message to System 'B'.  When System 'B' wishes to reply, it uses the message identifier of the 'request' message as the correlation identifier of the 'reply' message.  The reply queue used is either well known by both parties, or is communicated as a property on the request message.  For purposes of discussion, let's call this the "queueing contract". 

Both MSMQ and MQSeries have MessageId and CorrelationId properties on messages.  When looking at messages in a reply queue, System 'A' can peek at the messages, looking for a particular CorrelationId prior to issuing a receive.  Alternatively, it might use the CorrelationId as a look-up into working state of some sort.  To facilitate request-response interactions, MQSeries has had a ReceiveByCorrelationId API for a long while, whereas MSMQ added this in 3.0 (that is, on Windows XP and Windows 2003.) (Actual property and method names may vary in real life...)

There are, of course, many deployed systems in the wild that implement the queueing contract - using both MSMQ and MQSeries.  You may find yourself needing to integrate with these.  At first blush, it seems that consuming a service such as this should be a breeze from within BizTalk orchestrations - after all, accomplishing correlation is a first-class-citizen feature for BizTalk, so how tough can this be?

Correlation in BizTalk is indeed a first-class citizen...for data within your documents (or promoted message context.)  The classic example is to define a property schema that embodies a business identifier like "PONumber", and then visit all schemas that will be used across a set of message interactions - promoting the appropriate field in each as a "PONumber".  Then, a correlation type and correlation set are defined which reference that property, and Send and Receive shapes are set to either initialize or follow the correlation as appropriate.

The problem with an orchestration consuming the queuing contract we described earlier is that this contract occurs at the transport layer.  To be a consumer of the queueing contract, an orchestration would like to send a message, and initialize a correlation based on the MessageId...but the MessageId is produced further downstream, at the point an actual MSMQ or MQSeries message is generated by an adapter.  Moreover, an orchestration would subsequently like to receive a message, following an initialized correlation - but the CorrelationId isn't promoted by the MSMQ adapter (though it is for the MQSeries adapter...)

Solving for the MSMQ Adapter

The MSMQ Adapter gives us a small amount of help to get past this...We can in fact do our initial send operation through a solicit-response port (rather than a one-way port) and get back the MessageId that was generated by the adapter -- it actually comes back in a single-element document with a tag named "MSMQMsgId".  Starting here, the approach I took to solving the whole of the problem looked like this:

  1. Send a message through a MSMQ solicit-response port.  The response operation in the orchestration designer can be of type "String".
  2. On the response half of the solicit-response port, execute a pipeline & pipeline-component that extracts the returned MessageId and promotes it as the CorrelationId (using the standard MSMQ adapter namespace for that property.)  (For tracing purposes & useability, the MessageId is also returned in a <string> wrapper by the pipeline component rather than the native <MSMQMsgId> wrapper.)
  3. When the initial message (containing the correlation id in both content and context!) is received back into the orchestration, it is sent back out to initialize a correlation set (typed as MSMQ.CorrelationId.)  This Send shape is just a "dummy send"...it exists just to initialize the correlation, because that is the only means given to us in the orchestration world.  I used Patrick Wellink's "NOPE" Adapter for this purpose, but there would be other options as well (including Tomas' Null Send Adapter, which I just recently rediscovered and which apparently performs better under load.)
  4. Next, we receive the "real" response message - following the correlation that was just initialized.  Because MSMQ.CorrelationId is not promoted by default, the response is brought through a second pipeline component that performs that service for us.

See the diagram below (and the downloadable sample) for more detail. 


(click)

What can go wrong with this approach?  Well...there is race condition that can occur if the "real" response message (step 4 above) arrives before steps 2 and 3 can execute and establish the correlation (and associated instance subscription.)  In other words, if the "real" response message comes back before the orchestration has had a chance to express interest in that particular message, a routing failure will occur.  This might be highly unlikely for your scenario (given response times of the service you are interacting with) but it is something to test for, nonetheless.  (With BizTalk 2006's ability to route failed messages, you could potentially catch and retry in this scenario...)

(Note - if you are going to rely on the technique in the sample, consider asking Microsoft support for BizTalk 2004 QFE 1647, which addresses an issue with truncated correlation identifiers being returned to BizTalk...)

Solving for the MQSeries Adapter

Consuming the queueing contract with the MQSeries adapter for BizTalk can be done with a technique quite close to the one just discussed - but with a little less work.  The response to the initial solicit-response interaction returns with MQMD_MsgID already copied to a  MQSeries.BizTalk_CorrelationId property.  Likewise, the when receiving the "real" response message, MQMD_CorrelationId is copied to the MQSeries.BizTalk_CorrelationId property.  This means all correlation can be done with this one property - no pipelines/pipeline-components are needed!

From the documentation:


(click)

(The "dummy send" - though not pictured - would be required here as well to initialize the correlation set.)

In addition, there is a much cleaner solution that the BizTalk 2004 MQSeries adapter provides.  It turns out that MQSeries allows the "caller" to assign the message ID (unlike MSMQ), so within BizTalk, you can in fact set MQMD_MsgID and MQMD_CorrelationId to the same value prior to doing your initial send.  Now, you can initialize a correlation set based on MQMD_CorrelationId with the first outgoing message, and follow the correlation for the "real" response message.  Slick!

From the documentation:


(click)

Solving for the MQSeries Adapter in BizTalk 2006

Ahhhh, here we have what looks like real simplicity...There is a new feature in the BizTalk 2006 MQSeries adapter termed "Dynamic Receive" (referenced in the BizTalk 2006 Adapter Enhancements document.)  For a solicit-response port, Dynamic Receive allows context properties on the outbound message to determine which server, queue manager, and queue should be "watched" for the response message.  This is used in conjunction with a "match" option - which allows you to wait for a particular message based on CorrelationID (or any of several other properties, such as MessageID, GroupID, SequenceNumber, Offset, or MsgToken...)

Not only does this give us quite a bit of flexiblity for where response messages should be found (we don't need a fixed receive location anymore) but it also elminates the whole of the problem of implementing the "queueing" contract within orchestrations.  With this feature in place, an orchestration simply uses one solicit-response port, and the work is done.

Needless to say, it would be fantastic to get similar support from the MSMQ Adapter (at least the ability to have a single solicit-response port with a similar "match" criteria option, even without the dynamic receive location.)  But I don't think that is in the cards for BizTalk 2006...

Notes on the download:

  • See the BTMSMQCorrelation.PortBindings.xml file for the names of the two queues and two file directories that must be created for this sample.
  • Install Patrick Wellink's "NOPE" Adapter or choose a different strategy for dummy sends (like Tomas' Null Send Adapter.)
  • Use the included Deployment Framework-based deployment, or deploy manually.
  • To run, launch the "TestQueueServer" console app that will implement the queueing contract (request/response)
  • The sample will import and run just fine in BizTalk 2006, though you will have to deploy manually.  (Still working on the 2006 version of the deployment framework - more later...)

Hopefully this is helpful to those doing queueing work with BizTalk - enjoy!

Friday, November 04, 2005 4:10:26 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
BizTalk Insights
 Thursday, October 13, 2005

I had the pleasure of delivering a short talk at the Business Process Integration & Workflow Conference last week in Redmond.  The whole conference was great, especially meeting quite a few folks in person I'd only conversed with via email.  Being notified of MVP status for BizTalk on Friday was a great cap to the week!

Although the sample I presented during my talk isn't quite ready to release, the slides (on scatter/gather scenarios in BizTalk) can be downloaded here.

Thursday, October 13, 2005 3:46:25 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
General
Archive
<June 2006>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678
About the author:

Scott Colestock lives, writes, and works as an independent consultant in the Twin Cities (Minneapolis, Minnesota) area.

© Copyright 2008
Scott Colestock
Sign In
All Content © 2008, Scott Colestock
DasBlog theme 'Business' created by Christoph De Baene (delarou)