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.
Xslt snippet – Left pad a string
A quick xslt template to left pad a value:
<xsl:template name="prepend-pad">
<!-- recursive template to right justify and prepend the value with whatever padChar is passed in -->
<xsl:param name="padChar"> </xsl:param>
<xsl:param name="padVar"/>
<xsl:param name="length"/>
<xsl:choose>
<xsl:when test="string-length($padVar) < $length">
<xsl:call-template name="prepend-pad">
<xsl:with-param name="padChar" select="$padChar"/>
<xsl:with-param name="padVar" select="concat($padChar,$padVar)"/>
<xsl:with-param name="length" select="$length"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($padVar,string-length($padVar) - $length + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
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();
}
Debugging BizTalk instances – which one to attach to?
A good hint from Michael.
Determine the Process Id of a specific BTNTSVC.exe instance using the following command line:
tasklist /svc /fi "imagename eq btsntsvc.exe"
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().
Adding a Sql user that already exists
Occasionally I’ll need to copy a database over to my dev machine in order to be able to work offline.
USE <Target_Database> EXEC sp_change_users_login 'Update_One', '<Server_User>', '<Database_User>'
This will re-associate the Server Login with the specified Database Login.
Unlocking a file from TFS
Inevitably somebody on the team goes away on holidays and forgets to check everything into TFS (guilty, as charged!)
There’s no facility to unlock somebody else’s files through TFS Explorer, so we have to resort to the command line. Firstly, get the list of the user’s workspaces:
tf workspaces /server:tfsserver /owner:DOMAIN\offender /computer:*
This will list the workspaces “owned” by the offending little tyke absent user, which we will feed into the next command:
tf undo /server:tfsserver /workspace:workspacename;DOMAIN\offender $/path/to/file/to/unlock
Now you’re free to change the file at will, and reprimand your teammate when he gets back from his holiday, all tanned and relaxed.
Another FYI: just type in tf on the command line, and it will open up the appropriate help file. Sweet!
-
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


