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

2

3

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?

Metastasize answered 24/1, 2012 at 10:49 Comment(6)
Did you ever get any of the examples working without modification?Garnet
All the examples I found required one change to work, and that was to change the class to inherit Microsoft.Web.Services3.WebServicesClientProtocol instead of System.Web.Services.Protocols.SoapHttpClientProtocol. Once that change was made, everything worked fine. However, this change doesn't make a difference in my code, as I suspect it has to do with the serialisation step before invoking the method.Metastasize
Whenever I get into the situation where the example works, but my code does not, I start with the working example, then slowly refactor it into doing what I need my code to do. As soon as I break it, I back up to the previous working code, then more slowly move towards what I need. That way, I eventually find what's wrong.Garnet
Another problem...EDIT 2 above.Metastasize
Create a second question for that, but the answer is that prefixes don't matter, only the namespace that they represent. If they require a specific prefix, then they are seriously broken and not processing XML.Garnet
Yeah got the namespace issue sorted anyway. Don't know why they say they require specific prefixes, seems counter-intuitive, but fixed anyway. Updated the answer below.Metastasize
M
2

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 
Metastasize answered 25/1, 2012 at 12:24 Comment(1)
If you will clarify what you mean by "pre-serialised", then I will upvote.Garnet
D
1

I know it's been long time ago but...

I have the same thing happening and as it turns out my byte array gets in-lined when its 767 bytes or smaller :) And it gets moved to separate part when its 768 (12 * 8 * 8) bytes or larger.

So it just varies on content size.

Desolation answered 25/10, 2016 at 8:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.