1
votes

There is a remote service which I'm trying to get to send me messages via http POST requests using SOAP. I generated the service DTOs using the integrated in visual studio option "Add service reference".

Here's a sample of one autogenerated class:

[Route("/test", "POST")]
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, 
Namespace="http://www.reservationassistant.com/Booking/Types")]
public partial class UpdateBookingRequest
{

private Booking bookingField;

private string resortIdField;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public Booking Booking
{
    get
    {
        return this.bookingField;
    }
    set
    {
        this.bookingField = value;
    }
}

When I create my ServiceInterface methods and run my service, to go the metadata page I get this sample SOAP message

<UpdateBookingRequest>
  <bookingField>
         ....
  <bookingField>
<UpdateBookingRequest>

this is the code in my service interface class:

UpdateBookingResponse Post(UpdateBookingRequest request)
{
    // do stuff with request
    return null;
}

As you can probably imply by the auto-generated class the messages I receive will have tag names equal to the public properties in the generated DTOs. However this will never be possible, since for some reaason ServiceStack is trying to bind the incoming XML message elements to the private fields of the DTOs (sample SOAP message generated by the metadata page of my service - notice the "field" postfix after "booking"). How can I make the incoming messages to bind to the public properties and not the private fields?

1

1 Answers

1
votes

First if you want Typed C# Services I would highly recommend using the more resilient, versatile, cleaner and faster alternative in C# Add ServiceStack Reference. SOAP is a slow, fragile and bloated serialization format that should only be considered for legacy integrations.

By default ServiceStack uses .NET XML DataContract Serializer for XML or SOAP serialization so the behavior is dependent on .NET's XML DataContractSerializer implementation.

For handling SOAP it uses WCF's generic Message class which uses DataContractSerializer by default but you can switch to populate WCF's Message using XmlSerializer implementation by adding the [XmlSerializerFormat] attribute on your Request and Response DTOs.

You can request .NET's WCF svcutil to force generating DataContract or XmlSerializer classes using the /serializer command-line switch, e.g:

svcutil endpoint.wsdl /serializer:DataContractSerializer
svcutil endpoint.wsdl /serializer:XmlSerializer

Overriding ContentTypes

You can register a custom Content Type to override Xml Serialization used for XML requests, e.g. you can override it to use XmlSerializer implementation to handle XML requests with something like:

ContentTypes.Register(MimeTypes.Xml,
    (req, dto, stream) => {
        using (var xw = XmlWriter.Create(stream))
        {
            var ser = new XmlSerializerWrapper(dto.GetType());
            ser.WriteObject(xw, dto);
        }
    },
    (type, stream) => {
        using (var reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas()))
        {
            var serializer = new System.Xml.Serialization.XmlSerializer(type);
            return serializer.Deserialize(reader);
        }                    
    });

Metadata Preview for SOAP Requests

As you're inferring the behavior from the metadata preview please note that the preview isn't generated using WCF Serializer for SOAP Requests, the Request Body is generated using the DataContraceSerializer so it wont reflect the same output if using XmlSerializer implementation in WCF Message.