Introduction
In one of the projects that I recently worked with we had an opportunity to exchange insurance messages from our application to another application developed by another organization using the ACORD standards (https://www.acord.org/Pages/default.aspx). The partner with whom we were integrating was using an old version of the ACORD standard which was accepting messages to their web service endpoint using multipart - MIME message. Our application was built using C# and Microsoft has adopted a new standard called MTOM and doesn’t support MIME format anymore. So we had to find a way to send messages to our partner and the direction was not to use any third party tool for the same. There are several third party libraries available one such - MIMEKit – which can create MIME messages.
Background
Introduction to MIME Message
MIME – (Multipurpose Internet Mail Extensions) message lets user exchange different kinds of data between client and servers by specifying the type of data in the header. MIME an internet standard that was mainly designed to support some extended functionality to the email in the SMTP Format has been extended and put to use in HTTP as well. The client specifies the type of the data in the header (like plain text, xml, application/ excel etc.) which will let the server select appropriate applications / programs to handle the data. A sample MIME message would look like this
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==--
As you can see it begins with the Header – MIME-Version which specifies which version of the MIME message is being used. Then comes the Content-Type, there are multiple content-types supported by MIME (https://msdn.microsoft.com/en-us/library/ms527355(v=exchg.10).aspx – contains a list of content-type). The sample message above has the content-type: multipart/related which conveys to the server that the message is split into multi-parts and the message becomes meaningful once the all the parts are stitched together.
Introduction to ACORD
ACORD is a non-profit organization that provides data standards and implementation guidelines for the global insurance industry. ACORD schemas have been widely used and supported by major insurance industries.
Even though ACORD has updated its standards to start using MTOM and other latest technologies in transferring the messages, we had to retort to using Multi-part MIME message as the partner whom we were integrating with were sticking to the older version of the ACORD standard.
According to ACORD a sample POST request with an attachment would look something like this
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 Header
|
--MIME_boundary1234
Content-ID: xxxx
Content-Type: text/xml; charset=”utf-8”
Content-Length: nnnn
| MIME Part #1 Header
|
<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
| Business ACORD Message
|
--MIME_boundaryB0R9532143182121
Content-ID: <A01EFAE7-5490-43D0-AB6B-DAEF1671CDCC>
Content-Length: nnn
Content-Type: application/octect-stream; charset=”utf-8”
| MIME Part # 2 Header
|
<<Binary Content of the file>>
| Binary Attachment
|
-- MIME_boundary1234== | MIME Boundary End
|
Using the Code
Before we get into the code, there are several ways to get the SOAP request from C#(lots of articles are available in code project and other sites), hence the payload part which we need to create using the schema shared by ACORD can be done using those methods.
Now to create the rest of the Part of the message, we do the following
Import library
using System.Net.Http;
that provides programming interfaces for sending HTTP requests and receiving HTTP responses from a resource URL
Next set the properties like endpointURL
where we need to post the request and MIME boundary which would be used to specify the different parts of the message.
static string _endPointURL = "http://avalidwebservice.com";
static string _boundary = "=-glZ6jtnXmVAn68ZSF5H6Zw==";
Uri _endpoint = new Uri(_endPointURL);
HttpRequestMessage _requestMessage = new HttpRequestMessage(HttpMethod.Post, _endpoint);
Create a HTTP Request Message and Mark the HTTP Method as POST.
Create a MultipartContent
object by passing the content type as "related" and specify the boundary that we have set. Next is to create a httpContent
pass the soap message that we have captured / any other xml payload that we would like to send in the constructor of the HttpContent
.
Set the Headers of the HttpContent
by using the Headers property in the HTTPContent
Object. Few important properties that we need to set are "Content-Type" based on the content that we send we can specify the 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());
_multiPartContent.Add(_xmlContent);
For the list of complete set of Content-Type - https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types. Any other Headers that the receiver is expecting can be set in the Headers Property as it expects a key value to be present. Some of the commonly used Headers are
- Content-Transfer-Encoding - used to specify the encoding technique base64, 8 bit, 16bit etc
- Content-Description – used to specify any description that we need to send to the receiver
- Content-Disposition – used to specify content in-line or as attachment
Now set the multiPartContent to the HttpRequestMessage
. Create a HttpClient
object call the send asyc method to send the request message. Set the HttpCompletionOption.ResponseContentRead
and CancellationToken.None
HttpCompletionOption.ResponseContentRead
– makes sure that the operation would be completed after reading the entire response including the content.
CancellationToken.None
– makes sure that the operation cannot be cancelled.
_requestMessage.Content = _multiPartContent;
HttpClient httpClient = new HttpClient();
Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
HttpResponseMessage httpResponse = httpRequest.Result;
These code snippets are good enough to be able to send a MIME message to a web service endpoint using C#.