Biz(Talk)2

Talk, talk and more talk about BizTalk

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

November 6, 2009 Posted by Brett | BizTalk | , , | No Comments Yet

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)

September 18, 2009 Posted by Brett | BizTalk | | No Comments Yet

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.

August 24, 2009 Posted by Brett | BizTalk | | No Comments Yet

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();
 

 

}

 

July 29, 2009 Posted by Brett | BizTalk | , | No Comments Yet

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)

June 5, 2009 Posted by Brett | BizTalk | , , , , , , | No Comments Yet

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().

April 28, 2009 Posted by Brett | BizTalk | , , , | No Comments Yet

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

March 18, 2009 Posted by Brett | BizTalk | , , , | No Comments Yet

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.

September 30, 2008 Posted by Brett | BizTalk | , , | 1 Comment

Sending attachments through a Dynamic Send Port

I spent a bit of time getting a Dynmic Send Port to email a message to a recipient as a text attachment (regardless of the filename suffix).  The following documents the properties that need to be set on the message, and corresponding send port.
  1. Create the message (“msgEnvelope”) as a Multi-Part message, with the required message in the Message Body Part (“Attachment”)
  2. 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;
  3. Set the following properties of the Message Body Part (“Attachment”):
      // 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>;
  4. Set the following property on the Dynamic Send Port:
      // 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.

August 28, 2008 Posted by Brett | BizTalk | | No Comments Yet

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.

August 18, 2008 Posted by Brett | BizTalk | | No Comments Yet