I have a couple of other questions on here surrounding this area but they are a bit redundant now. Any answers to them would also be appreciated but this question is my main concern at the minute.
I have followed lots of examples of how MTOM/XOP works in WSE 3.0 and have set up my project exactly as it seems is required. I have a Byte array field that is designated as DataType:-base64Binary. In this I put the Byte array of the attachment I want to add. When I run the application and check the request, the data is encoded inline as base64, i.e. without the XOP Include element and associated MIME part.
My understanding of MTOM within WSE 3.0 was that, when encoding it will take any field designated as base64Binary and encode it as binary and move it to a MIME part, replacing it with an XOP Include element. That is to say, it just worked. But I have set the service, in the Reference file, to inherit Microsoft.Web.Services3.WebServicesClientProtocol
and have set the RequireMtom
flag to true, and it is still not encoding correctly.
Have I missed something here? Is there any other steps that should be implemented for this to work?
EDIT: After looking through my code for the 100th time, I am wondering if it might be due to the fact that I have to serialise the payload before running the ProcessMessage method. Does this sound like it could be a problem? The reason we have serialised is because the method we have to use accepts a "Payload" parameter which has a content property, this content property is an XMLElement property and the only way we can get this is to serialise the required class. But does this stop the MTOM recognising the data type of the base64 field and therefore not converted to binary with the MIME parts and XOP? Just really clutching at straws now.
EDIT 2: While I have a solution below, the third party company are now saying that our namespace prefixes are wrong! We have something like <q1:Attachment xmlns:q1="http://whatever" />
and they are demanding it be <s:Attachment xmlns:s="http://whatever" />
. Am I going mad or does that not matter? Is there a way I can tell it how to assign the namespace prefixes?
Ok I finally figured it out and it was to do with the serialisation before invoking the method. I rewrote the class that was passed in to the method so it didn't require an XMLElement as a property, and therefore a pre-serialised class, and passed that in. This works correctly, after only 3 or 4 weeks of work...If anyone wants more clarification I can try to get it down here.
EDIT: In response to John Saunders comment. When I say pre-serialised I mean that the class, containing the byte array, was serialised to XML before sending within the web method. This was due to the fact that the class that was being sent in the web method only accepted an XMLElement. I reworked the class, that was the parameter of the web method, to accept the other class without being serialised to XML beforehand.
Ie. This is how the class looks now. The processRepairOrder
field and PRO()
property were added and used instead of the anyField
Partial Public Class Content
Private anyField As System.Xml.XmlElement
Private idField As String
Private anyAttrField() As System.Xml.XmlAttribute
'This was added
Private processRepairOrder As ProcessRepairOrder
'This was added
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute([ElementName]:="ProcessRepairOrder", [Namespace]:="http://www.starstandards.org/STAR")> _
Public Property PRO() As ProcessRepairOrder
Get
Return Me.processRepairOrder
End Get
Set(ByVal value As ProcessRepairOrder)
Me.processRepairOrder = value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlAnyElementAttribute()> _
Public Property Any() As System.Xml.XmlElement
Get
Return Me.anyField
End Get
Set(ByVal value As System.Xml.XmlElement)
Me.anyField = value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlAttributeAttribute(DataType:="token")> _
Public Property id() As String
Get
Return Me.idField
End Get
Set(ByVal value As String)
Me.idField = value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlAnyAttributeAttribute()> _
Public Property AnyAttr() As System.Xml.XmlAttribute()
Get
Return Me.anyAttrField
End Get
Set(ByVal value As System.Xml.XmlAttribute())
Me.anyAttrField = value
End Set
End Property
End Class
With regards to the specific namespaces, we added another field to the required classes as such:
<System.Xml.Serialization.XmlNamespaceDeclarations()> _
Public xmlns As XmlSerializerNamespaces
Then we were able to add the namespace by using:
Dim ns As New Serialization.XmlSerializerNamespaces
ns.Add("s", "http://whatever")
class.xmlns = ns