Wednesday, December 30, 2009

Biztalk ESB Toolkit 2.0: Exception Management Gotchas - Create the Fault Message in the right place

I've been having a lot of fun lately with the ESB Toolkit. It's got lots of great features. One of my favorites is the Exception Management piece which is very easy to use and surpasses just about every EM framework that's already out there.

However, one small issue I've encountered is that when using the Exception Management framework, you must only create your fault message inside an Exception handler in your orchestration.

Code such as this:

FaultMsg = Microsoft.Practices.ESB.ExceptionHandling.ExceptionMgmt.CreateFaultMessage();

Anywhere besides inside an exception handler will cause your CPU to peg out and your orchestration to hang indefinitely. On one occasion, I've seen the process complete, but that was when I started it on a Friday afternoon and left for the weekend to find it complete on Monday morning. Other times, I've had to terminate the orchestration and then restart the host instance to clear it out and return my CPU to a less-stressed state.

The reason this happens is because, when creating the fault message, ESB sets a number of properties for you, some of which are retrieved from the instance of the System.Exception class that is accessible from within the Exception block.

I solved this issue by instantiating my own exception object and throwing it when I hit a state in my orchestration that meant we shouldn't go on anymore. If you want to send a fault message and just keep on going, though, as far as I can tell you're out of luck.

One other caveat--your own exception must be an instance of the System.Exception class. If you use your own custom exception, even if you inherit from System.Exception, ESB will throw an error similar to the one below when you submit it.

Error 115004: An unexpected error occurred while attempting to retrieve the System.Exception object from the ESB Fault Message.

So, unfortunately, you can't use custom exception types and work with the Exception Management Framework.

Thursday, December 3, 2009

Endlessly Looping Rules - After Effects

I can't speak for the entire world here, but this has happened to me more than once: when execution of a rule in the BRE hits an endless loop and memory and processor resources slowly get chewed up you may find that you'll have to do more than just kill off the offending BizTalk artifacts.

After everything manages to return to some state of normalcy, you may find that the BizTalkMgmtDb database and the BizTalkRuleEngineDb database are unavailable. When attempting to access, you get the standard unavailability-related message: "Cannot open database "BizTalkMgmtDb" requested by the login. The login failed." Your login is probably fine. The DB is just offline, but SQL Server doesn't seem to know it. Further attempts to look at it in SQL Server Management studio may yield a slightly different message regarding the inability to connect because of memory issues (which is probably because of the endless loop).

For me it was a simple solution. Just take the database offline and bring it back by right-clicking each of the aforementioned databases names in the SQL Server Management studio and select Tasks|Take Offline. Then bring it back online by selecting Tasks|Bring Online. That should clear the memory and get you up-and-running.

And double-check your rules to avoid endless loops.

Tuesday, December 1, 2009

XmlDocument Serialization in BizTalk 2009 (NOT!!!)

For those who are not already in the know on this, the System.Xml.XmlDocument object that we all know and love is, ironically, not serializable. Certainly a mistake or misunderstanding somewhere from Microsoft land, but as of version 3.5 of .NET, it's still missing this capability. You would think...

Anyway, this one has really bitten me in the rear in BizTalk as BizTalk serializes darn near everything. Where this became a problem has been in the creation of .NET components that are called from orchestration.

If you choose to use a class that has an XmlDocument object as one of its members, you'll find the message "Type 'System.Xml.XmlDocument' in Assembly 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable." This occurs anytime that BTS attempts to serialize a class that uses an XmlDocument as an instance member. Oddly enough, this won't apply to variables that are of the XmlDocument type in the orchestration as BTS knows it's not serializable and won't try.

There are a few ways around this dilemma:
1. Mark the member as NonSerializable. BTS will not attempt to serialize the object and you shouldn't see this error.
2. Create all methods that return XmlDocument types as static members. No instance == no persistence == no serialization.
3. Return XmlNodes instead. An XmlDocument can easily be converted to an XmlNode object which is serializable.
4. Build all your XmlDocuments from within the orchestration in Expression Shapes. It's ugly, but shouldn't cause you problems.
5. Make sure there are no persistence points in your orchestration. [Sarcastically] Yeah, right... Good luck with that ;-)

Oh, and don't forget to GAC your components and restart your Host Instances...

Monday, November 23, 2009

Project Creation Failed - BizTalk 2009 in Visual Studio 2008

I came across a problem today regarding the creation of a new BizTalk project in VS2008.

The symptom of the problem is when you try to create a project using the "Empty BizTalk Project" template, Visual Studio barfs on you and presents a "project creation failed' message in the message bar at the bottom of the screen. This behavior will occur when a patch is installed in Visual Studio. The patch installation process removes the .btproj type from the list of possible projects in the registry, causing this error to happen. So if you patch or apply a service pack to Visual Studio, be sure to check that you can still create BTS projects.

The solution is simple: update the registry entry to include the .btproj project type. The key is at:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Projects\{FAE04EC0-301F-11d3-BF4B-00C04F79EFBC}]

The entry is "PossibleProjectExtensions". Just change the value to add ";btproj" at the end and that will fix the problem.

Many articles out there recommend doing a Repair install of BizTalk to solve this problem. That would be big time over-kill as the only helpful thing that it would do is to update the registry entry as mentioned above. May as well go straight to the source of the problem and save yourself a little time and frustration. Of course, if you don't have the guts to touch the registry (and really, who doesn't?) then repair away...

Here's an article I found that presents this solution:

http://blogs.msdn.com/biztalkcrt/archive/2009/08/21/visual-studio-2008-fails-to-create-open-biztalk-projects.aspx

Don't Forget to use the Correct XPath Selector!

Working with the Business Rules Engine in BizTalk is more than just a little challenging at times. The tool is incredible in terms of what it can do and it is fast. The problem is that it isn't always the most intuitive thing to work with. I've been struggling with it a bit lately and found a very basic but simple truth--when having the BRE analyze a document for you, make sure you apply the correct XPath Selector when selecting nodes or creating Vocabularies.

In my most recent project, I have a document that contains a quantity node. What I wanted the BRE to do was to calculate the sum of all the quantities beneath a parent node and put the result in yet another node. The format was something like this:


<shipments>
<batch>
<shipment>
<quantityX>3</quantityX>
<quantityY>4</quantityY>
<shipment>
<shipment>
...Another shipment
<shipment>
<quantities>
<totalx>5</totalX>
<totaly>6</totalY>
<quantities>
</batch>
<batch>
...Another batch
</batch>
</shipments>


The rule followed this logic:

IF
/shipments/batch/quantities/totalX is equal to '0'

THEN
/shipments/batch/quantities/totalX = CalculateSum(
"/shipments/batch",
"./shipment/quantityX")

The CalculateSum function was simply .NET code that accepted a reference node and calculated the sum of all the items that matched an XPath expression beneath that node.

The problem here was the selector used for a quantityX node vs. the totalX node. If you simply "drag-and-drop" fields from a schema into the rules it will give you something like that above. However, you'll get an incorrect total because the rules engine creates an object in memory based on the selector. You can easily see which selector is being used by looking at the XPath Selector property when you select a node (lower left portion of the screen in the Business Rules Composer). If the Selector is different between parts of your IF/THEN work, you'll find that things won't always match up.

What had happened here was that the sum was being built on a selector of "/shipments/batch" with an XPath field of "quantityX". The rules engine was referencing a selector of "/shipments/batch/quantities". Since these were different, not all the quantities where added correctly. The rules engine wasn't passing the correct data into our CalculateSum function.

The solution is pretty simple, but not intuitive. You simply need to structure your XPath Selector and XPath Fields so that the selectors are holding the same reference point.
In the above example the Selector would be "/shipments/batch" for both items. The XPath fields would then be altered to reference from that point. For the total line, the XPath field would be "quantities/totalX". For the quantity line to be added the XPath field would be "/shipment/quantityX". But most importantly, both fields use the SAME XPATH SELECTOR!