Invalid content type for AS2 messages
Recently I ran into an issue with the Http ContentType used when sending messages using the As2EdiSend pipeline.
Using the standard out-of-the-box pipeline, the web content type will be set to “application/EDI-EDIFACT“, regardless of the value supplied in the Party as AS2 Receiver configuration. If your trading partner is using BizTalk as well, this is not an issue, as BizTalk, and probably some other AS2 servers, do not consider the content type before routing the AS2 payload for further parsing by an EDI interpreter.
However, our trading partner uses a specific AS2 server, Axway, that will only route to the EDI sub-system if the content type is, quite correctly, “application/EDIFACT” (note the small difference). This is the correct value, according to the RFC (link – see Section 4.2).
Our workaround was to add a custom pipeline component in between the EDI Assembler stage and the AS2 Encoder stage in a custom Pipeline. This custom component only does one thing, clears the IBaseMessage.BodyPart.ContentType property of the current message stream:
IBaseMessagePart bodyPart = pInMsg.BodyPart;
if ((bodyPart != null))
{
// Override the default content type with the one we want to use
pInMsg.BodyPart.ContentType = "";
}
return pInMsg;
By default, the EDI Assemble stage allocates a default value of “application/EDI-EDIFACT”. The AS2 Encoder will lookup the appropriate content type to use from the Party configuration, but only if the content type has not been supplied. As the EDI stage has already allocated a value, this “optional” value is rendered useless. By “clearing” the default value, we allow the AS2 stage to use the appropriate value
Writing to the event log from a BizTalk Orchestration
Some pointers when utilising DebugView to view debug output from your Orchestration:
- Make sure you write to System.Diagnostics.Trace, rather than System.Diagnostics.Debug
This ensures that the trace statements will not be compiled out of non-debug builds (unless of course, this is what you want to do!) - Use a static method on a helper class to provide a wrapper function. This also makes it easier to provide different levels of debug messages, eg. Debug, Information, Warning, Error
- Finally, ensure the “Capture Global Win32″ flag is set in DebugView. Without this, you’ll be scratching your head wondering where the messages have gone (speaking from experience)
Get the Instance ID of the current Orchestration
Using the following in an Expression shape will return the Instance Id of the Activating Orchestration instance.
instanceId = Microsoft.XLANGs.Core.Service.RootService.InstanceId;
Where instanceId is of type System.Guid.
Note, this will give you the Instance Id of the Activating Orchestration, not neccessarily the currently executing Orchestration. This distinction is important in the event of the currently executing Orchestration being called as a sub-orchestration via a Call Orchestration, or Start Orchestration shape.
Mocking an Http Request-Respose port
I occasionally want to be able to mock a Request-Response port, inthe event the target database is down, or I’m working locally.
The following ASP.NET snippet will allow me to point a two-way Send port at a local ASP.NET page, and gives me complete control over the mocked data I send back:
protected void Page_Load(object sender, EventArgs e)
{
String req = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
Debug.WriteLine(req);
FileStream outputFile = File.OpenRead(@”c:\temp\HttpListener\COPA_extract.xml”);
string extract = new StreamReader(outputFile).ReadToEnd();
//Write out the string to Response
Response.Write(extract);
// Need to call Response.End() or we get the standard Http DOCTYPE tags, etc
Response.End();
}
BizTalk Mapping – fixing huge maps
I have been working with several industry standard Xml schema definitions, specifically those defined by the UBL standard by OASIS (www.oasis-open.org). This organisation has a worthwhile, yet lofty, goal of defining a set of document standards that will cover the majority of communication needs for B2B.
The result of trying to be all things to all men is that the schemas defined are big. Like really, REALLY big, with a set of included schema file that run about 8-10 deep.
The problem with this, in the BizTalk world, is when you either generate an instance document from the schema, or attempt to map a document to a UBL schema document using the BizTalk Mapper. Due to the way the BizTalk handles default nodes, you end up with all default values being output into the destination document.
A quick, undocumented fix for this is to change the GenerateDefaultFixedNodes setting in the BizTalk Map. Where is this setting, you ask?
Open the .btm file using the “XML Editor”, rather than the default “BizTalk Mapper” (i.e. right-click, choose “Open With…”, then XML Editor). The root node of the map document is called “mapsource”, one of the attributes is called “GenerateDefaultFixedNodes”. Change this from “Yes” to “No”, save and close, and you’re done.
This undocumented trick brought one of our generated XSLT transforms down from a slightly ridiculous 50 Mb to an easily handled 11 Kb, and the transform execution time from 20 seconds down to about the 50 millisecond mark (on a virtual machine)
Received a “System.NotImplementedException” in custom pipeline component
While developing a custom pipeline component I began receiving a System.NotImplementedException when testing the pipeline from an Isolated Host.
After a bit of research, we found the following:
http://www.biztalkgurus.com/forums/p/11372/22514.aspx
Turns out the problem originates from the Http Adapter, which implements the Setter on the MessagePart.BodyPart.Data property, but not the Getter.
The solution was to change the code that retries the message stream from using MessagePart.BodyPart.Data to using MessagePart.GetOriginalDataStream().
Setting up the BizTalk SharePoint adapter
While deploying a solution that uses the BizTalk adapter for SharePoint, we ran into the following error in the EventLog on the BizTalk box:
Client found response content type of 'text/html; charset=utf-8', but expected 'text/xml
Not exactly helpful when you’re trying to remotely diagnose the root problem!
After a little fact checking, it turns out that we had configured the SharePoint adapter correctly on the SharePoint box, however the BizTalk side of the configuration was trying to contact the SharePoint adapter on the default port 80. We had installed the adapter into the non-default web site on the SharePoint machine, and it was listening in on a different port.
So, the actual message being returned to BizTalk was the actual HTML page spat back from IIS, telling us that the requested endpoint did not exist (i.e. we got the port wrong), but the client proxy end of the BizTalk adapter was expecting an Xml document, not an HTML document
Problems with PropertyBag in custom pipelines
Some advice written by one of my colleagues, Zeb, who spent some time wrestling with a custom pipeline
I was recently tasked with building a custom pipeline component. I hit the net to look for some samples on doing this, and the first thing that I noticed was that there appeared to be a million blogs on how to do this, and they were all using the exact same code – right down to even using the same GUID for their class!There are plenty of things I could write (and maybe I will), but the biggest issue I had was that none of them were really elaborating on the saving and extraction of custom properties. The basics were simple (implement IPersistPropertyBag), but as is so often the case what can seem simple, often turns out to be far from it! (Although it does tend to become simple and obvious in hindsight)
It was a long journey, and hard to debug, as the symptoms weren’t immediately pointing to the cause. So, below are the two biggest issues I had with the PropertyBag, and how to work around them:
Issue 1: Properties are visible in BizTalk, but not in Visual Studio
Now, this one really didn’t make sense at first, and honestly, it still doesn’t! I know the “how”, but not the “why”. Basically, Visual Studio uses reflection on the class to look for public properties and assumes that they are the properties that can be modified from within Visual Studio. BizTalk on the other hand looks at the actual serialized [sic] properties saved into the pipeline (i.e. if you look in the .btp file “Properties” node inside the component).
So, if you do what I did and move your properties into a seperate class (which I did because I wanted to make two versions of the component – one inheriting from FFDasmComp and one from XMLDasmComp), you need to be aware that you also need to expose them in the calling class as seperate public properties or they will not be visible in Visual Studio.
Issue 2: PropertyBag.Read method returning NULL
This was a strange one, as I was getting inconsistent behaviour. Sometimes my component would work, other times it wouldn’t, and my code changes did not appear to be impacting on the success rate.
The lucky break came when I noticed that the Load method was being called twice, and each instance was returning different values. It appears that BizTalk was calling Load once with the information that was saved when the pipeline was created in Visual Studio, and then a second time to get the customized [sic] values that were modified in the BizTalk Administration Console. The problem here is that if you don’t modify a value in BizTalk, it doesn’t get saved to that property bag, so the read will return NULL.
The way around this is to do the first read and use it to load default values for your properties, and then on the second read only overwrite those values if the Read returns a non-NULL value. I did this by creating a “GetProperty” function that accepted the PropertyBag, the key to read and a default value (which was loaded with the previously read value if available). If Read returned NULL (or error), I loaded the default value.
Thanks for the good work, Zebba.
Sending attachments through a Dynamic Send Port
- Create the message (“msgEnvelope”) as a Multi-Part message, with the required message in the Message Body Part (“Attachment”)
- Set the following properties of the Envelope Message:
msgEnvelope(SMTP.Subject) = <Email Subject>;
msgEnvelope(SMTP.From) = <Sender Email>;
msgEnvelope(SMTP.SMTPHost) = <Email Host name>";
// This is the default value
msgEnvelope(SMTP.SMTPAuthenticate) = 0;
// Set the message text included in the email
msgEnvelope(SMTP.EmailBodyText) = <Text in body of email>;
// Important - This is required if the EmailBodyText is set
msgEnvelope(SMTP.EmailBodyTextCharset) = "utf-8";
// A value of '1' means include Message Body Part as email attachment
msgEnvelope(SMTP.MessagePartsAttachments) = 1;
// Important - Change this MIME type if not sending a Text file
msgEnvelope.Attachment(Microsoft.XLANGs.BaseTypes.ContentType) = "text/plain";
// Set the Filename of the attachment
msgEnvelope.Attachment(MIME.FileName) = <Physical name of the attachment>;
// We set the Email Address on the Port itself
Dynamic_Send_Port(Microsoft.XLANGs.BaseTypes.Address) = <recipient email address>;
The Send Port is then configured to use a custom Send Pipeline containing a Flat File assembler for the message schema to convert the message into the flat file.
PersistenceException
I finally managed to work out why I was receiving the dreaded “PersistenceException”. There’s not a lot of helpful information surrounding this one, you just get:
Microsoft.XLANGs.Core.PersistenceException: Exception occurred when persisting state to the database
Most of the posts I Googled for were incorrectly diagnosing it as occuring due to no subscription being set up in the Message Box. However, this was on a late bound Send-Receive port, and the subscription appeared good in the Group Hub.
Finally, I worked it out! It was being caused due to a duplicate subscription in the Message Box.
I had another Orchestration that was direct bound on the same Message Type that I was trying to send via the Send Port. Somehow, this causes BizTalk to get in a huff, but not really give any worthwhile error information.
So, whenever you find yourself with a “PersistenceException”, try looking for a duplicate subscription.
-
Archives
- November 2009 (1)
- September 2009 (1)
- August 2009 (2)
- July 2009 (2)
- June 2009 (1)
- April 2009 (2)
- March 2009 (2)
- February 2009 (1)
- January 2009 (1)
- September 2008 (3)
- August 2008 (4)
-
Categories
-
RSS
Entries RSS
Comments RSS


