问题描述
在我们第一次尝试解决这个问题之后,我们决定使用Greg Forsythe的代码。下面是完整的C#代码。我还展示了来自邮递员的请求(它工作得很好)和来自BizTalk的请求(不工作)。但正如你所看到的,我们非常非常接近解决这个问题。我还必须指出,我们在管道中不再有任何MIME组件。
public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
{
return CreateMultipartMIME(pContext, pInMsg);
}
private IBaseMessage CreateMultipartMIME(IPipelineContext pContext, IBaseMessage pInMsg)
{
// Boundary
string separator = Guid.NewGuid().ToString();
// New message
IBaseMessage outMsg = pContext.GetMessageFactory().CreateMessage();
outMsg.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
// Create messagepart (BodyPart)
IBaseMessagePart multiPart = pContext.GetMessageFactory().CreateMessagePart();
multiPart.ContentType = "text/plain";
multiPart.Data = CreateMIME(pInMsg, separator);
// Add messagepart as BodyPart
outMsg.AddPart("multiPart", multiPart, true);
outMsg.BodyPart.ContentType = string.Format("multipart/form-data; boundary={0}", separator);
outMsg.Context.Promote("ContentType", "http://schemas.microsoft.com/BizTalk/2003/http-properties", string.Format("multipart/form-data; boundary={0}", separator));
return outMsg;
}
private Stream CreateMIME(IBaseMessage pInMsg, string separator)
{
Stream mimeStream = new VirtualStream();
TextWriter writer = new StreamWriter(mimeStream);
// MIME-header
// form-data: Bodypart
writer.WriteLine(string.Format("--{0}", separator));
writer.WriteLine("Content-Disposition: form-data; name="data"; filename="Dk_{5AA9547A-E103-40CD-A2F4-6B77F010E570}.xbrl"");
writer.WriteLine("Content-Type: application/xml");
writer.WriteLine();
// Read BodyPart stream
using (StreamReader reader = new StreamReader(pInMsg.BodyPart.GetOriginalDataStream()))
{
while (!reader.EndOfStream)
{
writer.WriteLine(reader.ReadLine());
}
}
// form-data: email
writer.WriteLine(string.Format("--{0}", separator));
writer.WriteLine("Content-Disposition: form-data; name="email"");
writer.WriteLine("Content-Type: text/plain");
writer.WriteLine();
writer.WriteLine("[email protected]");
writer.WriteLine(string.Format("--{0}", separator));
writer.Flush();
mimeStream.Position = 0;
return mimeStream;
}
现在邮递员的请求(正在处理):
Content-Type: multipart/form-data; boundary=--------------------------035085236562027409735938
Content-Length: 299420
----------------------------035085236562027409735938
Content-Disposition: form-data; name="data"; filename="Dk_{5AA9547A-E103-40CD-A2F4-6B77F010E570}.xbrl"
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8"?>
<!- ---- Lots of removed xbrl ---- ->
</xbrli:xbrl>
----------------------------035085236562027409735938
Content-Disposition: form-data; name="email"
Content-Type: text/plain
[email protected]
----------------------------035085236562027409735938--
最后是我们当前从BizTalk到接收系统的请求:
--26f685f3-5804-44dd-b76b-b3de6391bda1
Content-Disposition: form-data; name="data"; filename="Dk_{5AA9547A-E103-40CD-A2F4-6B77F010E570}.xbrl"
Content-Type: application/xml
<?xml version="1.0" encoding="utf-8"?>
<!- ---- Lots of removed xbrl ---- ->
</xbrli:xbrl>
--26f685f3-5804-44dd-b76b-b3de6391bda1
Content-Disposition: form-data; name="email"
Content-Type: text/plain
[email protected]
--26f685f3-5804-44dd-b76b-b3de6391bda1
下面的错误消息I我收到的所有信息:
A message sent to adapter "WCF-WebHttp" on send port "A_Sxxx_REST" with URI "https://xxx/xxx" is suspended.
Error details: System.Net.WebException: The remote server returned an unexpected response: (400) Bad Request.
{"error":{"status":400,"message":"HTTP 400 Bad Request"}}
MessageId: {DA019D0C-3C31-4C2C-BEA4-FBFCDF646984}
InstanceID: {B44ED7E8-67EE-4C35-BAC8-3D81553D6AA2}
那么,有没有人知道为什么邮递员请求的第一部分没有出现在我们编程的解决方案中?
推荐答案
解决方案
在解决这个问题整整三周之后,我们终于设法解决了这个问题。对于任何需要快速可靠的解决方案的人,我们的经验、最终代码和一些解释如下。public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
{
return CreateMultipartMIME(pContext, pInMsg);
}
private IBaseMessage CreateMultipartMIME(IPipelineContext pContext, IBaseMessage pInMsg)
{
// Boundary
string separator = "231422701264181268539385ABC";
// Create new message
IBaseMessage outMsg = pContext.GetMessageFactory().CreateMessage();
outMsg.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
// Create messagepart (BodyPart)
IBaseMessagePart multiPart = pContext.GetMessageFactory().CreateMessagePart();
multiPart.Data = CreateMIME(pInMsg, separator);
outMsg.Context.Write("HttpHeaders", "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties", string.Format("content-type: multipart/form-data; boundary={0}
accept: application/json
", separator));
return outMsg;
}
private Stream CreateMIME(IBaseMessage pInMsg, string separator)
{
Stream mimeStream = new VirtualStream();
TextWriter writer = new StreamWriter(mimeStream);
// MIME-header
// form-data: Bodypart
writer.WriteLine(string.Format("--{0}", separator));
writer.WriteLine("Content-Disposition: form-data; name="data"; filename="Dk_{5AA9547A-E103-40CD-A2F4-6B77F010E570}.xbrl"");
writer.WriteLine("Content-Type: application/xml");
writer.WriteLine();
// Read BodyPart stream
using (StreamReader reader = new StreamReader(pInMsg.BodyPart.GetOriginalDataStream()))
{
while (!reader.EndOfStream)
{
writer.WriteLine(reader.ReadLine());
}
}
// form-data: email
writer.WriteLine(string.Format("--{0}", separator));
writer.WriteLine("Content-Disposition: form-data; name="email"");
writer.WriteLine("Content-Type: text/plain");
writer.WriteLine();
writer.WriteLine("[email protected]");
writer.WriteLine(string.Format("--{0}--", separator));
writer.Flush();
mimeStream.Position = 0;
return mimeStream;
}
现在,是什么让这段代码真正工作呢?实际上,有几件事。我们的第一个问题是接收系统发回一个JSON确认。但是我们的http标头清楚地指出,我们只接受应用程序/XML(http接受标头)内容。因此,我们尝试设置Accept标头,并设法将其设置正确。但现在的问题是,我们的Content-Type标头反转为默认的Content-Type:Application/XML。因此,为了使两个头文件都正确,我们必须将它们合并到一个代码行中。现在,标题看起来很不错,Content-Type设置为Form-Data/MultiPart,Accept设置为application/json,application/xml。outMsg.Context.Write("HttpHeaders", "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties", string.Format("content-type: multipart/form-data; boundary={0}
accept: application/json
", separator));
邮递员:BizTalk:下一个要解决的问题是边界分隔符。在比较Fiddler中的视图时,我几乎偶然发现了这个问题。
邮递员:BizTalk:区别现在很明显,但我们实际上发送了一个相当大的文件,所以我们没有看到最后一部分。我们一直认为一切都很好,不同之处在于BizTalk和Postman发送文件的方式。我们大错特错了。当我们第一次使用最简约的文件时,我们终于可以看到电子邮件部分本应以单独的形式存在,但实际上位于数据部分之下。难怪我们的接收系统总是返回400条错误的请求消息。我们终于明白,我们没有正确设定我们的边界。
根据SO MIME boundary article,MIME分隔符必须以某种方式显示,才能真正将消息视为多部分。我们被Fiddler误导了,因为我们总是把邮递员和BizTalk的原始数据进行比较。它们看起来几乎一样。但有一些我们没有考虑到的差异。
边界必须按如下方式使用:
--boundary
1. body-part
--boundary
2. body-part
--boundary
3. body-part
--boundary--
前缀--
对于消息中使用的每个边界都是强制的,尾部--
对于结束边界(关闭分隔符)是强制的。这表示消息部分是最后一个部分,消息应在此处结束。
修复此问题后,我们得到以下结果:
BizTalk:最后,表单数据和多部分实际上看起来都很好。我们修复的最后一个小问题是接收系统需要一个文件名。这可以通过以下代码轻松解决:
writer.WriteLine("Content-Disposition: form-data; name="data"; filename="Dk_{5AA9547A-E103-40CD-A2F4-6B77F010E570}.xbrl"");
现在,关于物理发送端口的最后几句话。我们使用的是WCF-WebHttp端口,并且在端口传输属性中没有设置出站http标头。它是空,而且应该是空的,因为我们在代码中设置了所有内容。这三周的旅程真是太棒了。我真的希望这篇文章能在未来对某些人有所帮助。感谢每一个试图以任何方式提供帮助的人。非常感谢。
这篇关于BizTalk错误请求(多部分表单数据)第2部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!