There seems to be a lot of confusion regarding SOAP and attachments. Since
I've done a lot of research lately on the topic, I thought I'd post some
information that may be useful to others.
My goal was to write AXIS services that could accept/send attachments
from/to SOAP clients written using the "SOAP Toolkit 3.0" and the "Web
Services Enhancements 1.0" (sometimes called the WSDK) (both from Microsoft).
Here I'll roughly describe what I went through to achieve this goal.
-------------------------------
The "Web Services Enhancements 1.0" was easiest. The sample program in...
<WSE-install>\Samples\QuickStart\Clients\Attachments
shows you how to send an "unreferenced" attachment. This is an attachment
that is *not* referenced by the soap envelope.
The first thing needed is to add the following code to their
EchoAttachment.Echo() method before the "this.invoke()" line.
----------------------------------------------------
// Needed to not confuse Apache AXIS.
this.RequestSoapContext.Path.MustUnderstand = false;
----------------------------------------------------
Without this, a WS-Routing SOAP header with a MustUnderstand value of true
will cause AXIS to generate a fault (since it doesn't understand it).
In order to specify the URL of your choice, in AttachmentsClient.Run()
method, right after...
EchoAttachment serviceProxy = new EchoAttachment();
add a line like...
----------------------------------------------------
serviceProxy.Url = "http://localhost:8080/axis/services/YourServicePath";
----------------------------------------------------
This sample shows how to send an attachment but not how to receive one. To
receive an unreferenced attachment, after the method call (in
AttachmentsClient.cs), you can add lines like...
----------------------------------------------------
if (serviceProxy.ResponseSoapContext.Attachments.Count >= 1)
{
attachment = serviceProxy.ResponseSoapContext.Attachments[0];
...
----------------------------------------------------
So now we should have a C# SOAP client that sends/accepts a DIME attachment
and won't confuse AXIS (with its special WS-Routing SOAP header).
(I used Visual Studio 7.0 to build this project)
We now need to write an AXIS service that can receive/send unreferenced
attachments. Luckily, this is easy...
In your service, you can use the current MessageContext to iterate over any
attachments that were sent to you and also to add any attachments you want
in your response.
Here is some sample code that looks for the first received attachment and
sends it back to the client.
----------------------------------------------------
org.apache.axis.MessageContext context =
org.apache.axis.MessageContext.getCurrentContext();
java.util.Iterator i = context.getMessage().getAttachments();
if (i != null)
{
if (i.hasNext())
{
Object attachmentPartCandidate = i.next();
if (attachmentPartCandidate instanceof
org.apache.axis.attachments.AttachmentPart)
{
org.apache.axis.attachments.AttachmentPart attachmentPart =
(org.apache.axis.attachments.AttachmentPart) attachmentPartCandidate;
try
{
javax.activation.DataHandler dh = attachmentPart.getDataHandler();
// Do what you will with dh!
// Build up an AttachmentPart to send in the response. For this
// sample, we'll just re-use the one we were sent.
org.apache.axis.Message responseMessage = context.getResponseMessage();
responseMessage.addAttachmentPart(attachmentPart);
}
catch (javax.xml.soap.SOAPException e)
{
// Ignore
}
}
}
}
----------------------------------------------------
----------------------------------------------------
----------------------------------------------------
Now we'll move on to MS SOAP Toolkit 3.0. This toolkit has a lot of
machinery. There are both high and low-level APIs for dealing with your
SOAP message and attachments.
The low-level attachment client examples are in...
<MSSOAP3.0>\Samples30\Attach\Client\SrSz\WshVbs
These programs are scripts (wscript, vbscript, etc..) that build up the
SOAP message directly. They don't require a WSDL.
I hacked on one of them to produce the following script which works with
the AXIS sample urn:EchoAttachmentsService (after an AXIS source code
change; more on this later).
[Start of samtest.vbs]
------------------------------------------------------------------------------
' I combined parts of GetPicture.vbs and PutPicture.vbs along with some
' code of my own.
Option Explicit
' This is the URL to which messages will be sent.
'Const END_POINT_URL =
"http://MSSoapSampleServer/MSSoapSamples30/Attach/Service/SrSz/AspVbs/PutPicture.asp"
Const END_POINT_URL =
"http://sbrow1d:9876/axis/services/urn:EchoAttachmentsService"
Dim Connector
Dim Reader
Dim Parser
Dim Serializer
Dim Attachment
Dim ReceivedAttach
Dim RcvdAttachments
Dim Node
Dim NodeList
Dim ScriptPath
Dim Composer
Dim FileAttachment
Dim res
' Create an HTTP connector and set the end point URL.
Set Connector = CreateObject("MSSOAP.HttpConnector30")
Connector.Property("EndPointURL") = END_POINT_URL
Connector.Property("SoapAction") =
"http://tempuri.org/Attach/action/Attach.echo"
' Create a file attachment object and set it's FileName property.
Set FileAttachment = CreateObject("MSSOAP.FileAttachment30")
ScriptPath = "D:\\VS.NET\\MSSOAP3.0\\Samples30\\Attach\\Client\\SrSz\\WshVbs\\"
FileAttachment.FileName = ScriptPath & "SamplePicture.jpg"
' Create DIME composer and serializer objects, then initialize the
' serializer with the composer.
Set Composer = CreateObject("MSSOAP.DimeComposer30")
Set Serializer = CreateObject("MSSOAP.SoapSerializer30")
Serializer.InitWithComposer Connector.InputStream, Composer
' Write out the SOAP Envelope and Body start tags.
Serializer.StartEnvelope
Serializer.StartBody
' Start the method element.
Serializer.StartElement "echo"
' Write out the element that references the picture attachment.
' AXIS doesn't seem to care what this element name is.
Serializer.StartElement "Picture"
Serializer.AddAttachmentAndReference FileAttachment
Serializer.EndElement
Serializer.EndElement
' Write out the SOAP Envelope and Body end tags.
Serializer.EndBody
Serializer.EndEnvelope
' Tell the serializer that we are finished providing all message
' content (both the SOAP envelope and all attachments).
Serializer.Finished
'-----------------------------------------------------------
' Create a DimeParser30 object. This object will find the SOAP Envelope
' and any DIME attachments in the request message and make them available
' though the SoapReader30 object.
Set Parser = CreateObject("MSSOAP.DimeParser30")
' Create a SoapReader30 object. This object will provide access to the
' SOAP Evelope contents and any attachments identified by the DimeParser30
' object.
Set Reader = CreateObject("MSSOAP.SoapReader30")
res = Reader.LoadWithParser(Connector.OutputStream, Parser)
Set Node = Reader.RPCParameter("returnqname")
Set Attachment = Reader.GetReferencedAttachment(Node)
' Save the attachment to a file. Indicate that any existing file
' with this can can be replaced.
ScriptPath = "D:\\VS.NET\\MSSOAP3.0\\Samples30\\Attach\\Client\\SrSz\\WshVbs\\"
Attachment.SaveToFile ScriptPath & "ReceivedPicture.jpg", True
------------------------------------------------------------------------------
[End of samtest.vbs]
The tricky part here was extracting the attachment from the response.
As I mentioned, above, getting this to work required changing one line of
AXIS source code so let me explain this.
The referenced attachment that AXIS sends out has an "href" attribute in
the body that looks something like...
cid:987623414253512151413145151
The actual DIME attachment has an ID that does *not* have the "cid:"
prefix. It appears that the MS SOAP Toolkit 3.0 is confused by this since
it is expecting a literal match.
In order to get this to work, I had to change...
org\apache\axis\attachments\AttachmentPart.java
as follows...
public String getContentIdRef() {
// Original version.
//return Attachments.CIDprefix + getContentId();
// The below version allows MSSOAP Tookit 3.0 to work. They get
confused because
// the href attribute has something like "cid:1234...." but the
attachment itself
// just has 1234... *without* the cid: prefix.
return getContentId();
}
I compiled just this file and placed its .class file in...
<axis-install>\webapps\axis\WEB-INF\classes\org\apache\axis\attachments
After restarting Tomcat, this altered .class file kicked in and produced
responses without the "cid:" prefix.
With this in place, the samtest.vbs script above worked correctly.
Microsoft seems to use a prefix of "uuid:" but they use it both in the href
attribute and in the attachment id whereas
AXIS uses "cid:" in the href attribute but not in the attachment id.
I'll now move on to the high-level API. The high-level attachment example
is in...
<MSSOAP3.0>\Samples30\Attach\Client\Rpc\Cpp
The high-level API dynamically reads a WSDL file and exposes (via COM)
interfaces for the SOAP methods described in the WSDL file.
This is kind of clunky since you have to write a lot of code to make the call.
I started by modifying the Attach.wsdl file in this sample to have some new
entries.
[Start of modified Attach.wsdl]
-------------------------------------------------------
<?xml version='1.0' encoding='UTF-8' ?>
<!-- Generated 04/22/02 by Microsoft SOAP Toolkit WSDL File Generator,
Version 3.00.1122.0 -->
<definitions
name='Attach'
targetNamespace='http://tempuri.org/Attach/wsdl/'
xmlns:wsdlns='http://tempuri.org/Attach/wsdl/'
xmlns:typens='http://tempuri.org/Attach/type/'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:stk='http://schemas.microsoft.com/soap-toolkit/wsdl-extension'
xmlns:dime='http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/'
xmlns:ref='http://schemas.xmlsoap.org/ws/2002/04/reference/'
xmlns:content='http://schemas.xmlsoap.org/ws/2002/04/content-type/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
<types>
<schema
targetNamespace='http://tempuri.org/Attach/type/'
xmlns='http://www.w3.org/2001/XMLSchema'
xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
elementFormDefault='qualified'>
<import namespace='http://schemas.xmlsoap.org/soap/encoding/'/>
<import namespace='http://schemas.xmlsoap.org/wsdl/'/>
<import namespace='http://schemas.xmlsoap.org/ws/2002/04/reference/'/>
<import namespace='http://schemas.xmlsoap.org/ws/2002/04/content-type/'/>
<complexType name='UnknownBinaryContent'>
<simpleContent>
<restriction base='base64Binary'>
<annotation>
<appInfo>
<!--
You may use one or more of the following elements to describe the
binary content:
<content:type value='(URI identifying type)'/>
<content:mediaType value='(MIME media type)'/>
<content:documentType value='(QName of XML document)'/>
-->
<content:mediaType value='application/octet-stream'/>
</appInfo>
</annotation>
</restriction>
</simpleContent>
</complexType>
</schema>
</types>
<message name='Attach.PutPicture'>
<part name='Picture' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutPictureResponse'>
</message>
<message name='Attach.echo'>
<part name='returnqname' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.echoResponse'>
<!--
The name here doesn't seem to matter as long as it isn't
returnqname because, if it is, this value appears on the
parameterOrder attribute and because it sees it in both
the input and output portions, it thinks it is an in/out
parameter and that messes things up apparently.
-->
<part name='Sam' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.GetPicture'>
</message>
<message name='Attach.GetPictureResponse'>
<part name='Result' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutXml'>
<part name='SampleXml' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutXmlResponse'>
</message>
<message name='Attach.GetXml'>
</message>
<message name='Attach.GetXmlResponse'>
<part name='Result' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutRecordset'>
<part name='Recordset' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutRecordsetResponse'>
</message>
<message name='Attach.GetRecordset'>
</message>
<message name='Attach.GetRecordsetResponse'>
<part name='Result' type='typens:UnknownBinaryContent'/>
</message>
<message name='Attach.PutMultiple'>
<part name='OtherParam' type='xsd:string'/>
</message>
<message name='Attach.PutMultipleResponse'>
</message>
<message name='Attach.GetMultiple'>
<part name='OtherParam' type='xsd:string'/>
</message>
<message name='Attach.GetMultipleResponse'>
</message>
<message name='Attach.PutGetMultiple'>
<part name='OtherParam' type='xsd:string'/>
</message>
<message name='Attach.PutGetMultipleResponse'>
</message>
<portType name='AttachSoapPort'>
<operation name='PutPicture' parameterOrder='Picture'>
<input message='wsdlns:Attach.PutPicture'/>
<output message='wsdlns:Attach.PutPictureResponse'/>
</operation>
<operation name='echo' parameterOrder='returnqname'>
<input message='wsdlns:Attach.echo'/>
<output message='wsdlns:Attach.echoResponse'/>
</operation>
<operation name='GetPicture' parameterOrder=''>
<input message='wsdlns:Attach.GetPicture'/>
<output message='wsdlns:Attach.GetPictureResponse'/>
</operation>
<operation name='PutXml' parameterOrder='SampleXml'>
<input message='wsdlns:Attach.PutXml'/>
<output message='wsdlns:Attach.PutXmlResponse'/>
</operation>
<operation name='GetXml' parameterOrder=''>
<input message='wsdlns:Attach.GetXml'/>
<output message='wsdlns:Attach.GetXmlResponse'/>
</operation>
<operation name='PutRecordset' parameterOrder='Recordset'>
<input message='wsdlns:Attach.PutRecordset'/>
<output message='wsdlns:Attach.PutRecordsetResponse'/>
</operation>
<operation name='GetRecordset' parameterOrder=''>
<input message='wsdlns:Attach.GetRecordset'/>
<output message='wsdlns:Attach.GetRecordsetResponse'/>
</operation>
<operation name='PutMultiple' parameterOrder='OtherParam'>
<input message='wsdlns:Attach.PutMultiple'/>
<output message='wsdlns:Attach.PutMultipleResponse'/>
</operation>
<operation name='GetMultiple' parameterOrder='OtherParam'>
<input message='wsdlns:Attach.GetMultiple'/>
<output message='wsdlns:Attach.GetMultipleResponse'/>
</operation>
<operation name='PutGetMultiple' parameterOrder='OtherParam'>
<input message='wsdlns:Attach.PutGetMultiple'/>
<output message='wsdlns:Attach.PutGetMultipleResponse'/>
</operation>
</portType>
<binding name='AttachSoapBinding' type='wsdlns:AttachSoapPort' >
<stk:binding preferredEncoding='UTF-8'/>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='PutPicture'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.PutPicture'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Picture'/>
</input>
<output>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
<operation name='echo'>
<soap:operation soapAction='http://tempuri.org/Attach/action/Attach.echo'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='returnqname'/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Sam'/>
</output>
</operation>
<operation name='GetPicture'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.GetPicture'/>
<input>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Result'/>
</output>
</operation>
<operation name='PutXml'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.PutXml'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='SampleXml'/>
</input>
<output>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
<operation name='GetXml'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.GetXml'/>
<input>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Result'/>
</output>
</operation>
<operation name='PutRecordset'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.PutRecordset'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Recordset'/>
</input>
<output>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
<operation name='GetRecordset'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.GetRecordset'/>
<input>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/closed-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='Result'/>
</output>
</operation>
<operation name='PutMultiple'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.PutMultiple'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/open-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='OtherParam'/>
</input>
<output>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
<operation name='GetMultiple'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.GetMultiple'/>
<input>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='OtherParam'/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/open-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
<operation name='PutGetMultiple'>
<soap:operation
soapAction='http://tempuri.org/Attach/action/Attach.PutGetMultiple'/>
<input>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/open-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts='OtherParam'/>
</input>
<output>
<dime:message
layout='http://schemas.xmlsoap.org/ws/2002/04/dime/open-layout'
wsdl:required='true'/>
<soap:body
use='encoded'
namespace='http://tempuri.org/Attach/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
parts=''/>
</output>
</operation>
</binding>
<service name='Attach' >
<port name='AttachSoapPort' binding='wsdlns:AttachSoapBinding' >
<soap:address
location='http://MSSoapSampleServer/MSSoapSamples30/Attach/Service/Rpc/IsapiCpp/Attach.WSDL'/>
</port>
</service>
</definitions>
-------------------------------------------------------
[End of modified Attach.wsdl]
Just search for "echo" in the file above to see the new entries I
introduced to reflect the AXIS sample urn:EchoAttachmentsService.
There were a few tricky parts. See inline comments for more details.
I then modified the OnPutPicture() method in the AttachCliRpcCpp.cpp sample
file as follows...
[Start of modified OnPutPicture() method]
-------------------------------------------------------
void CAttachCliRpcCppDlg::OnPutPicture()
{
HRESULT hr;
try
{
// Display the hourglass mouse pointer.
BeginWaitCursor();
// Create a FileAttachment30 object.
IFileAttachmentPtr pFileAttachment;
hr = pFileAttachment.CreateInstance(__uuidof(FileAttachment30));
if( FAILED(hr) ) RaiseError(L"Cannot create MSSOAP.FileAttachment30
object.", hr);
// Set the file attachment object's file name property to the
// name of the file that will be sent as an attachment.
CString FileName = m_AppPath + _T("\\SamplePicture.jpg");
pFileAttachment->FileName = _bstr_t(FileName);
// Perform the PutPicture operation.
EXCEPINFO excepinfo;
DISPID dispid;
DISPPARAMS params;
const int CARGS = 1; // One argument.
_variant_t args[CARGS];
_variant_t result;
//WCHAR *pName = L"PutPicture";
WCHAR *pName = L"echo";
unsigned int uArgErr;
// Use this to specify your own SOAP URL.
m_pSoapClient->ConnectorProperty["EndPointURL"] =
_variant_t("http://sbrow1d:9876/axis/services/urn:EchoAttachmentsService");
// Get id of "PutPicture" method.
hr = m_pSoapClient->GetIDsOfNames(
IID_NULL,
&pName,
1,
LOCALE_SYSTEM_DEFAULT,
&dispid);
//if( FAILED(hr) ) RaiseError(L"Cannot get id of PutPicture.", hr);
if( FAILED(hr) ) RaiseError(L"Cannot get id of echo.", hr);
excepinfo.wCode = 0;
excepinfo.wReserved = 0;
excepinfo.bstrSource = 0;
excepinfo.bstrDescription = 0;
excepinfo.bstrHelpFile = 0;
excepinfo.dwHelpContext = 0;
excepinfo.pvReserved = 0;
excepinfo.pfnDeferredFillIn = 0;
excepinfo.scode = 0;
params.cArgs = CARGS;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = 0;
params.rgvarg = args;
// File attachment object argument. The type will be set to VT_DISPATCH.
args[0] = (IDispatch*)pFileAttachment;
hr = m_pSoapClient->Invoke(
dispid, // ID of PutPicture
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
¶ms,
&result, // Expect return value.
&excepinfo,
&uArgErr);
if( FAILED(hr) ) RaiseError(L"PutPicture failed.", hr, excepinfo, params,
uArgErr);
// Return value is expected to be an IDispatch interface to an
// ReceivedAttachment30 object.
if( result.vt != VT_DISPATCH ) RaiseError(L"echo did not return an object.");
// Get an IReceivedAttachment interface pointer for the return value.
IReceivedAttachmentPtr pReceivedAttachment;
hr = result.pdispVal->QueryInterface(&pReceivedAttachment);
if( FAILED(hr) ) RaiseError(L"echo did not return an IReceivedAttachment
interface", hr);
// Save the picture content to a file.
FileName = m_AppPath + "\\ReceivedPicture.jpg";
pReceivedAttachment->SaveToFile(_bstr_t(FileName), VARIANT_TRUE);
// Remove the hourglass mouse pointer.
EndWaitCursor();
// Display an success message.
MessageBox("Success!");
}
catch( _com_error Error )
{
// Remove the hourglass mouse pointer.
EndWaitCursor();
// Display an error message.
DisplayError(_T("Cannot put picture."), Error);
}
}
-------------------------------------------------------
[End of modified OnPutPicture() method]
Mostly the changes needed were...
- Call "echo" instead of "PutPicture"
- Specify URL of my choice.
- Extract the returned attachment (grabbed that code from the
OnGetPicture() method)
Build the project, run it, and click the Put Picture button to exercise
this code.
This worked for me but, again, only after tweaking AXIS to not put the
"cid:" prefix on outgoing attachment references.
[Wrap up]
------------------------------------------------------
I'll post a short mail to the SOAP developers list so they know about the
code change I had to make.
I'm still waiting for a tool what will take a WSDL file that uses the DIME
extensions and cranks out a SOAP client that automatically handle
attachments. AXIS could do this now. All of the infrastructure is
there. Hopefully a future release will add this support.
I hope this posting will be of help to others. I know it would've saved me
a lot of research.
Thanks
Sam Brow