Recently someone asked me what is the best way of sending a file to a webservice, given that we know that MTOM is the way forward and Soap with Attachments (SwA) and WS-Attachments/DIME are now deprecated. I agree with many others that using base64 encoding to send the attachment within the SOAP message is the best approach (until we get MTOM).
Background
For those who haven’t followed the attachment saga (Omri has a good overview or the whole sorry story), the basic problems with the previous ways of sending attachments was that they were slow to process and more importantly, placed the attachments outside of the envelope, making it hard to compose attachments with the SOAP processing model and WS-Security specifications. MTOM solves this by defining the rules that allow the content to be sent outside the message as binary (rather than base64) data, but using ‘includes’ to allow that content to be treated as part of the SOAP envelope XML Infoset.
(As an aside, does anyone else find it funny that even though SOAP was based on the analogy of an envelope, the original spec didn’t define where to put the address (hence WS-Addressing) and the three initial attempts at attachments didn’t think to put the attachments inside the envelope? But, I digress.)
MTOM to the rescue (soon)
The future looks bright since WSE 3.0 and Indigo will support MTOM but what’s the best approach today?
One way is to use WSE 2.0’s support for WS-Attachments/DIME, another is to look at SwA (though as Matt Powell points out, SwA was only ever a W3C Note and even that has expired). Since Microsoft doesn’t have any product support for SwA you would have to write your own, or contact a group who have already developed a .NET SwA solution.
Base64 encoding: a good solution for today
Another approach that will work today is to stick with base64 encoded text rather than using SwA or DIME. There are several benefits to using this approach. Martin Gudgin says the schema definition for ‘[an] element definition will work with both XML 1.0 based SOAP services and those that support MTOM as a serialization format.’ Simon Fell agrees that base64 encoding will make it easier to change in future. Matt Powell summarises it well in his great MSDN Article on Web Services, Opaque Data and the Attachments problem when he says:
Base 64 encoding is probably the best way to pass opaque data if transport size efficiency is not your first concern. It will work seamlessly with higher-level WS-* protocols and is smaller than a standard XML encoding.
So the only disadvantage is that the content is base64 encoded which means that it is larger (by about 4/3). Though, as Marc Hadley mentions, you’d have to Base64 encode an attachment even with MTOM if you wanted to sign it.
Simple implementation
Another benefit is that base64 encoding is simple to implement. Here’s an example ASMX endpoint that accepts one way messages containing a file. As you can see the file is defined as a Byte array:
[WebMethod]
[SoapDocumentMethod(OneWay=true)]
public void SaveFile(Byte[] file)
{
// Write the Byte array out using a FileStream
}
The message then looks like this on the wire. As can be seen the content is all inside the envelope, making it easy to use WSE and WS-Security to sign and encrypt the attachment if required.
<xml version="1.0" encoding="utf-8" ?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<SaveFile xmlns="urn:benjaminm.net:sendbinary">
<file>R0l…slyvLIbabN mzMbAtjJsyfPgAA7< span>file>
</< span>SaveFile>
</soap:Body>
</soap:Envelope>