How to process “multipart/form-data” message submitted to BTSHttpReceive.dll
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
NOTE: This article is migrated from Blog AsiaTech
Date: 2009-8-27 11:05 AM
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
When use a form based web page as the below to submit a XML file to one BizTalk HTTP receive location using XMLReceive pipeline, It would fail to validate and suspended.
<html>
<body>
<FORM NAME="myForm" ACTION="https://localhost/btarnhttpreceive/btshttpreceive.dll?httpmime" ENCTYPE="multipart/form-data" METHOD="post">
<INPUT TYPE="file" NAME="myFile" >
<INPUT TYPE="submit" VALUE="Upload File" >
</FORM >
</body>
</html>
If check the suspended message, you would see the message format similar as the below:
-----------------------------7d91593580102
Content-Disposition: form-data; name="myFile"; filename="D:\HttpMimeTest\1.xml"
Content-Type: text/xml
<ns0:TestRoot xmlns:ns0="https://HttpMimeTest.Schema1">
<TestRecord>
<TestField>TestField_0</TestField>
</TestRecord>
</ns0:TestRoot>
-----------------------------7d91593580102—
It looks like a MIME encoded message, but if develop a customized pipeline which add a MIME/SMIME decoder before the XML disassembler, it would fail to decode the message since actually the format is not complete/standard MIME format.
Solution:
Develop a pipeline component which is added before the MIME/SMIME decoder at the same stage, the component would add the missed MIME header as the below to the beginning of an incoming message to construct a complete MIME message so the MIME/SMIME decoder can decode it, retrieve the packed XML and pass it to the XML disassembler at the next stage in the pipeline.
MIME-Version: 1.0
Content-Type: multipart/form-data; boundary=---------------------------7d91593580102
The FixMsg pipeline component sample which is located at the folder [BizTalk Installation Folder] \ SDK\Samples\Pipelines\CustomComponent\FixMsg can be used to add a fixed preconfigured string to the beginning of a message. It has to be modified in order to add a dynamic string such as boundary part as the above. The trick is the Content-Type including boundary can be retrieved from the incoming message context property InboundHttpHeaders. The following is the demo modified function Execute in the FixMsg.cs which read the Content-Type head with boundary from the context property InboundHttpHeaders and then append it to the preconfigured prependData which is “MIME-Version: 1.0”.
public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
IBaseMessagePart bodyPart = inmsg.BodyPart;
if (bodyPart!=null)
{
byte[] prependByteData = ConvertToBytes(prependData);
byte[] appendByteData = ConvertToBytes(appendData);
string headersString = inmsg.Context.Read("InboundHttpHeaders", "https://schemas.microsoft.com/BizTalk/2003/http-properties").ToString();
string[] headers = headersString.Split(new Char[] {'\r','\n' }, StringSplitOptions.RemoveEmptyEntries);
string MimeHead=String.Empty;
bool Foundit=false;
for (int i=0;i<headers.Length;i++)
{
if (headers[i].StartsWith("Content-type:", true, null))
{
MimeHead = headers[i];
Foundit = true;
break;
}
}
if (Foundit)
{
StringBuilder sb = new StringBuilder();
sb.Append(prependData);
sb.Append("\r\n");
sb.Append(MimeHead);
sb.Append("\r\n");
prependByteData = ConvertToBytes(sb.ToString());
}
Stream originalStrm = bodyPart.GetOriginalDataStream();
Stream strm = null;
if (originalStrm != null)
{
strm = new FixMsgStream(originalStrm, prependByteData, appendByteData, resManager);
bodyPart.Data = strm;
pc.ResourceTracker.AddResource( strm );
}
}
return inmsg;
}
The following is the screen capture for the customized pipeline project.
Regards,
XiaoDong Zhu
Comments
- Anonymous
October 08, 2011
Good post - Anonymous
July 31, 2013
Very clear and very helpful! Thanks a lot! All I need to do was modfify 'Content-type:' to 'Content-Type:' in the code modification.