65.9K
CodeProject 正在变化。 阅读更多。
Home

从 C# 向 Web 服务端点发送 MIME 消息

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (2投票s)

2017年1月20日

CPOL

4分钟阅读

viewsIcon

24698

在当前环境中仍存在一些遗留的 Web 服务,它们期望以 MIME 格式接收请求消息。本文介绍了一种更简单的方法,无需使用任何第三方组件,即可使用 MIME 格式向遗留 Web 服务发送消息。

引言

在我最近参与的一个项目中,我们有机会通过 ACORD 标准(https://www.acord.org/Pages/default.aspx)将保险消息从我们的应用程序交换到另一个组织开发的应用程序。我们集成的合作伙伴使用的是一个旧版本的 ACORD 标准,该标准通过 multipart - MIME 消息接受到其 Web 服务终结点发送的消息。我们的应用程序是使用 C# 构建的,而 Microsoft 已采用新的 MTOM 标准,不再支持 MIME 格式。因此,我们必须找到一种方法将消息发送给我们的合作伙伴,并且要求不能使用任何第三方工具。市面上有许多第三方库,例如 MIMEKit,可以创建 MIME 消息。

背景

MIME 消息简介

MIME – (Multipurpose Internet Mail Extensions) 消息允许用户通过在标头中指定数据类型来在客户端和服务器之间交换不同类型的数据。MIME 是一种互联网标准,最初是为了在 SMTP 格式中支持电子邮件的一些扩展功能而设计的,后来也被扩展并用于 HTTP。客户端在标头中指定数据类型(如纯文本、XML、application/excel 等),这将使服务器能够选择合适的应用程序/程序来处理数据。示例文本消息如下所示:

MIME-Version: 1.0
Content-Type: multipart/related; boundary=--=-glZ6jtnXmVAn68ZSF5H6Zw==
 
--=-glZ6jtnXmVAn68ZSF5H6Zw==
Content-Type: text/plain; charset=utf-8
Content-ID: 291169ef-d733-4989-a39f-2a5619d09c97
 
Request from Party A to Party B
 
--=-glZ6jtnXmVAn68ZSF5H6Zw==
 
Content-Type: text/xml
Content-ID: 8365146c-c9bc-47f5-8487-e6b34611d078
 
<ac:Attachments><ac:Attachment><ac:Document><ac:DocumentReference>TS43289061M1</ac:DocumentReference><ac:DocumentVersion>1</ac:DocumentVersion><ac:FileId>Shima Re/Seg Acct QGF001- RECLAM 8971884.xlsx</ac:FileId><ac:FileSize><ac:NumUnits>48</ac:NumUnits><ac:UnitMeasurementCd>KB</ac:UnitMeasurementCd></ac:FileSize><ac:DocumentTypeCd>document_broker_invoice</ac:DocumentTypeCd><ac:Description>Shima Re/Seg Acct QGF001- RECLAM 8971884</ac:Description></ac:Document></ac:Attachment></ac:Attachments>

/9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAASUkqAAgAAAAEABoBBQABAAAAPgAAABsBBQABAAAARgAAACgBAwABAAAAAgAAADEBAgASAAAATgAAAAAAAABgAAAAAQAAAGAAAAABAAAAU 

--=-glZ6jtnXmVAn68ZSF5H6Zw==
Content-Type: application/octect-stream
Content-ID: e49c391b-57ca-4d1b-afd2-c109dbc624d6
--=-glZ6jtnXmVAn68ZSF5H6Zw==--

如您所见,它以标头 MIME-Version 开头,该标头指定了使用的 MIME 消息版本。接下来是 Content-Type,MIME 支持多种 Content-Type(https://msdn.microsoft.com/en-us/library/ms527355(v=exchg.10).aspx – 包含 Content-Type 列表)。上面的示例文文的消息的 Content-Type 为:multipart/related,这会告知服务器消息被拆分成多个部分,并且只有当所有部分都拼接在一起时,消息才具有意义。

ACORD 简介

ACORD 是一个非营利组织,为全球保险行业提供数据标准和实施指南。ACORD 架构已被主要的保险行业广泛使用和支持。

尽管 ACORD 已更新其标准,开始使用 MTOM 和其他最新的消息传输技术,但我们不得不求助于使用多部分 MIME 消息,因为我们集成的合作伙伴仍在使用旧版本的 ACORD 标准。

根据 ACORD,带有附件的示例文本 POST 请求如下所示:

POST http://partner-test.com/api/request HTTP/1.1
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary= MIME_boundary1234
; type=text/xml; start=xxxxx
Host: partner-test.com
Content-Length: nnnn
SOAPAction: " PostRq"

HTTP 标头

--MIME_boundary1234
Content-ID: xxxx
Content-Type: text/xml; charset=”utf-8”
Content-Length: nnnn

MIME 部分 #1 标头

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope" SOAPENV
encodingStyle="http://schemas.xmlsoap.org/soap/encoding">
<SOAP-ENV:Body>

SOAP

<ac:PostRq xmlns="http://www.ACORD.org/Standards/AcordMsgSvc/Inbox"
xmlns:ac="http://www.ACORD.org/Standards/AcordMsgSvc/1.4.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.ACORD.org/Standards/AcordMsgSvc/1.4.0
AcordMsgSvc_v-1-4-0.xsd">
<ac:Sender>
<ac:PartyId>urn:duns:123456789</ac:PartyId>
<ac:PartyRoleCd>Broker</ac:PartyRoleCd>
</ac:Sender> …….. </ac:PostRq

业务 ACORD 消息

--MIME_boundaryB0R9532143182121
Content-ID: <A01EFAE7-5490-43D0-AB6B-DAEF1671CDCC>
Content-Length: nnn
Content-Type: application/octect-stream; charset=”utf-8”

MIME 部分 # 2 标头

<<文件二进制内容>>

二进制附件

-- MIME_boundary1234==

MIME 边界结束

Using the Code

在深入研究代码之前,有多种方法可以从 C# 获取 SOAP 请求(Code Project 和其他网站上有许多相关文章),因此,我们可以使用这些方法来创建 ACORD 共享的模式所需的有效负载部分。

现在,为了创建消息的其余部分,我们执行以下操作:

导入库

using System.Net.Http;

该库提供用于从资源 URL 发送 HTTP 请求和接收 HTTP 响应的编程接口。

接下来,设置属性,例如我们要发送 POST 请求的 endpointURL 和将用于指定消息不同部分的 MIME 边界。

static string _endPointURL = "http://avalidwebservice.com";
static string _boundary = "=-glZ6jtnXmVAn68ZSF5H6Zw==";
Uri _endpoint = new Uri(_endPointURL);
HttpRequestMessage _requestMessage = new HttpRequestMessage(HttpMethod.Post, _endpoint);

创建 HTTP 请求消息,并将 HTTP 方法标记为 POST。

通过传递“related”作为内容类型并指定我们设置的边界,来创建一个 MultipartContent 对象。接下来是创建一个 httpContent,在 HttpContent 的构造函数中传递我们捕获的 SOAP 消息或我们想要发送的任何其他 XML 有效负载。

使用 HTTPContent 对象中的 Headers 属性设置 HttpContent 的标头。我们需要设置的几个重要属性是“Content-Type”,根据我们发送的内容,我们可以指定 Media Type。

MultipartContent _multiPartcontent = new MultipartContent("Related",boundary);
HttpContent _xmlContent = new StringContent("")  -- here you can pass the xml stored as string / 
 
_xmlContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
_xmlContent.Headers.Add("Content-ID",Guid.NewGuid().ToString());
 
//Add any other content headers that you want to add here  
//_xmlContent.Header.Add("key""value");
 
_multiPartContent.Add(_xmlContent);

完整的 Content-Type 列表可以在 https://mdn.org.cn/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types 找到。接收方期望的任何其他标头都可以设置在 Headers 属性中,因为它期望存在键值对。一些常用的标头包括:

  • Content-Transfer-Encoding – 用于指定编码技术,例如 base64、8bit、16bit 等。
  • Content-Description – 用于指定我们需要发送给接收方的任何描述。
  • Content-Disposition – 用于指定内容是内联还是作为附件。

现在,将 multiPartContent 设置到 HttpRequestMessage。创建一个 HttpClient 对象,调用 SendAsync 方法发送请求消息。设置 HttpCompletionOption.ResponseContentReadCancellationToken.None

HttpCompletionOption.ResponseContentRead – 确保操作在读取包括内容在内的整个响应后完成。

CancellationToken.None – 确保操作无法被取消。

_requestMessage.Content = _multiPartContent;                

HttpClient httpClient = new HttpClient();

Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);

HttpResponseMessage httpResponse = httpRequest.Result;

这些代码片段足以使用 C# 将 MIME 消息发送到 Web 服务终结点。

© . All rights reserved.