.netsoapmtomwsexop

WSE 3.0 - Byte array being encoded as Base64 and not "MTOM-ing" to binary


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?


Solution

  • 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