Wednesday, January 15, 2014

Routing suspended messages and subscribing to them with filters

So I found that in my Suspended Messages queue I was getting a lot of the same message. The failed message was not coming out of an orchestration(the orchestration it was generated in from was catching all exceptions) but instead was coming from the send port the orchestration was bound to. What happens in these circumstances is that the orchestration doesn't suspend since that's being caught but the message that goes out from the port(in this case a web service) was failing and ending up in the queue. I wanted to make a note of this in the originating orchestration and then somehow make these suspended messages disappear. 

First of all I made a note in the originating orchestration (or rather a coworker did) by simply parsing the exception generated's message property in the catch scope and writing to the event viewer(and/or log4net). 

Second, I marked the send port in question, the one bound to the orchestration, such that failed messages from this port were routed to the message box. The messages in question are the requests that got sent out, not the responses(which didn't really exist since the requests were what was responsible for gumming up the works). Here's a pic;

and here is an explanation of what happens(though it could be more clear).
http://msdn.microsoft.com/en-us/library/aa578516(BTS.10).aspx

Basically the failed message will not be put into the suspended queue but instead will be put into the message box for routing. Interestingly enough the normal promoted properties(that orchestrations would use for routing I believe) are not promoted. This means it goes back to the message box and things aren't subscribed to it that might normally be. There is however an ErrorReport object with a bunch of properties(listed in the link above). One of these is ErrorType which is, for all such 'failed messages' that get put in the message box, set to "FailedMessage". 

What this all means is that we can mark these ports, and then either create a send port that has got a filter(see above) and have the send port just dump the message to a folder(that we then clean up).

Alternatively we can write an orchestration that has a receive shape with the same filter. There's a short explanation of how best to go about this orchestration here near the bottom(post by Greg.Forsythe);
http://social.msdn.microsoft.com/Forums/en-US/c7328eec-6b66-409c-82af-788920bf64b4/failed-message-routing-without-orchestration-accessing-errorreport-properties

The nice thing about this last option in general is that nothing is generated; the formerly suspended message will disappear into the orchestration and no record will be left. The downside is that you cannot modify the filter expression in the receive shape at runtime(for example if you want to further filter what gets picked up by the orchestration).

Wednesday, October 16, 2013

A safe way to delete things from BizTalkMgmtDb ?

On occasion I see something like this;

Schema referenced by Map '<Namespace>.<MappName>' has been deleted. The local, cached version of the BizTalk Server group configuration is out of date. You must refresh the BizTalk Server group configuration before making further changes. (Microsoft.BizTalk.Administration.SnapIn)

When it doesnt go away by refreshing the Server group I tend to try restarting, etc. If that doesnt work it usually means something in the biztalk database is out of date or messed up. I have gone in a few times to bts_item table in BizTalkMgmtDb to look for whatever the offending item is and from there you can delete it out of MapSpec or wherever else. I found a great link online covering this specific case here . The sql code used was (once youre connected to the BizTalkMgmtDb);

 
SELECT itemid FROM [BizTalkMgmtDb].[dbo].[bts_item] where FullName ='<whatever the map is>'
 
Then
 
Delete from BizTalkMgmtDb.dbo.bt_MapSpec where itemid ='<whatever the map itemid was>'.


Tuesday, October 8, 2013

xpath and biztalk; really?

stringTmp = "string(/*[local-name()='SXPTaskUpdate' and namespace-uri()='SXPTaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']/text())";
stringTmp3 = xpath(Message_1 , stringTmp);


and

stringTmp = "string(/*[local-name()='SXPTaskUpdate' and namespace-uri()='SXPTaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer'])";
stringTmp3 = xpath(Message_1 , stringTmp);


returns: Customer_0

stringTmp2 = System.Convert.ToString(xpath(Message_1 , "/*[local-name()='SXPTaskUpdate' and namespace-uri()='SXPTaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']"));

and


stringTmp2 = System.Convert.ToString(xpath(Message_1 , "/*[local-name()='SXPTaskUpdate' and namespace-uri()='SXPTaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']/text()"));

returns: Microsoft.XLANGs.Core.Part+ArrayBasedXmlNodeList

One good source I've found is this:
http://social.technet.microsoft.com/wiki/contents/articles/6944.biztalk-orchestrations-xpath-survival-guide.aspx

Tuesday, May 14, 2013

Two things I learned about direct bound ports


When you directly bind to the message box, your messages will get picked up by subscribing orchestrations and send ports and then returned (see diagram below which I got from http://www.c-sharpcorner.com/UploadFile/john_charles/Introduction_to_Biztalk_Server09072007152846PM/Introduction_to_Biztalk_Server.aspx). One thing I learned is that if you have two orchestrations subscribing to a message they will both get it. Another thing you might notice from the diagram is that if your orchestration recieves and sends back the same message then it will pick it up again(and again, and again...). This infinite loop is a rather common peril of message box use.

Thursday, March 14, 2013

Enterprise SSO problem

So I was having an issue after creating a local user on my box with all kinds of privledges. The issue was that this user couldnt access the secret on the master secret server(ESSO was running as this local user);
Error Code: 0xC0002A1F, Cannot perform encryption or decryption because the secret is not available from the master secret server. See the event log for related errors.

The consensus online is to restore the master secret. This means going to the ESSO snap in (or cmd) and right click 'Restore'. Then locate the backup file you want to restore from. The location of your backup files(*.bak) in case you don't already have one you set up or you don't know, is:

 C:\Program Files\Common Files\Enterprise Single Sign-On\SSOXXXX.bak 

where the XXXX is generated by Biztalk when it creates the backups. I used the most recent backup file. I didnt know the password, then noticed, from the password secret, that the password was an old users password. After using the correct password i successfully restored and everything worked fine. I will say that if you use the wrong password you get an error of 'Bad Data' from ESSO.
 

Tuesday, January 29, 2013

xpath in expression shapes

 xpath is a notation for returning specific elements found in xml. It is very useful. I will go over a few problems I had getting it to work in Biztalk 2010 and the solutions I came accross.
First of all suppose you have some message in Biztalk,
  <ns0:TaskUpdate xmlns:ns0="TaskUpdateTN">
  <ns0:Task>
  <ns0:CallID>CallID_0</ns0:CallID>
  <ns0:Number>125</ns0:Number>
  <ns0:Status>
  <ns0:Name>Name_0</ns0:Name>
  </ns0:Status>
  <ns0:Customer>Customer_0</ns0:Customer>
  <ns0:WorkOrderNumber>WorkOrderNumber_0</ns0:WorkOrderNumber>
  <ns0:RequiredSkills1>Skill</ns0:RequiredSkills1>
  </ns0:Task>
  </ns0:SXPTaskUpdate>

 and you want to extract a certain element of the xml, say the 'Customer' element.

1) Create a couple of strings in the orchestration, tempStr and customerStr.

2) Use the schema properties to grab the xpath of the element you want,
 /*[local-name()='TaskUpdate' and namespace-uri()='TaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']. Notice you dont need every last namespace in the xpath, just enough so it can safely find what you're looking for.

3) Open up an expression shape and type:
 tempStr="string(/*[local-name()='TaskUpdate' and namespace-uri()='TaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']/text())";
 customerStr = xpath(Message_1, tempStr);


 And youre done; 'customerStr=Customer_0'. In some cases the 'string()' is not neccesary. The '/text()' however is, or else you would get 'customerStr=<ns0:Customer>Customer_0</ns0:Customer>' instead of just 'customerStr=Customer_0'. If you have a list of Customer elements in your message and you want the 3rd element in that list then your xpath will be '...[local-name()='Customer'][3]/text()'.


 If you want to assign a certain element in the Message to a value, say the 'Customer' element, to "John Doe". Change step 3) above to:

3)Open up an expression shape and type:
 tempStr="/*[local-name()='TaskUpdate' and namespace-uri()='TaskUpdateTN']/*[local-name()='Task']/*[local-name()='Customer']";
 xpath(Message_1, tempStr)="John Doe";


 Here a 'string()' doesnt work. Also an important thing to remember is if Message_1 is from a Message Part then you will have to write 'xpath(Message_1.part1,tempStr)="John Doe"'.

Thursday, December 6, 2012

Could not establish trust relationship for the SSL/TLS ...

If you are consuming a web service in Biztalk and calling it through ports, etc you may come across a certificate for a wsdl that's out of date or wrong in some other way. in this case you get the following error;

"Could not establish trust relationship for the SSL/TLS ... "

In code its easy enough to bypass this by trusting all certs.


      //Trust all certificates      System.Net.ServicePointManager.ServerCertificateValidationCallback =
     ((sender, certificate, chain, sslPolicyErrors) => true);

However in Biztalk its much harder; I tried adding this code in an expression shape but had no luck. After searching around a bunch I found the following server wide solution. Add the following to your BtsNtSvc.exe.config (see bold):

<?xml version="1.0" ?>
<configuration>
<system.net>
<settings>
<servicePointManager checkCertificateName="false" checkCertificateRevocationList="false" />
</settings>
</system.net>

...


Obviously this is really risky security wise; only use it for development.