Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use an XML attribute in a MessageContract type?

Tags:

c#

soap

xml

wcf

A note up front: I cannot change the format of the SOAP requests coming in, as they are fixed by international standards (weeeeeeeee).

I have a SOAP request that comes into my WCF service looking something like this:

<s:Body>
    <Request version="1.0">
        <data someOtherVersion="1.1">
            ...
        </data>
    </Request>
</s:Body>

Up to now, we've been using System.ServiceModel.Channels.Message objects directly, which is kind of a pain. We're trying to move to using strong types that look like this:

[MessageContract(IsWrapped = false)]
public class Request
{
    [MessageBodyMember]
    [XmlAttribute("version")]
    public string Version;

    [MessageBodyMember]
    [XmlElement("data")]
    public SomeOtherType Data;
}

[MessageContract(IsWrapped = false)]
public class Response
{
    [MessageBodyMember]
    [XmlAttribute("version")]
    public string Version;

    [MessageBodyMember]
    [XmlElement("data")]
    public SomeOtherType ResponseData;
}

[ServiceContract]
[XmlSerializerFormat]
public interface Service
{
    [OperationContract(Action = "request", ReplyAction = "response")]
    Response ServiceOperation(Request req);
}

Unfortunately, when we try to start up, we get an error saying "An unhandled exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll

Additional information: XmlSerializer attribute System.Xml.Serialization.XmlAttributeAttribute is not valid in Version. Only XmlElement, XmlArray, XmlArrayItem and XmlAnyElement attributes are supported in MessageContract when IsWrapped is false."

Interestingly, setting "IsWrapped" to true gives the same error. Is there a way to serialize XML attributes in message contract types, or is using wrappers our only option here?

like image 385
Lee Crabtree Avatar asked Jul 28 '14 15:07

Lee Crabtree


1 Answers

Unfortunately the only way I found to achieve this is to use a wrapper class

[MessageContract(IsWrapped = false)]
public class Response
{
    [MessageBodyMember(Name = "Response", Namespace = "Http://example.org/ns1")]
    public ResponseBody Body { get; set; }

    public Response(){}


    public Response(ResponseBody body)
    {
        Body = body;
    }
}

[XmlType(AnonymousType = true, Namespace = "Http://example.org/ns1")]
public class ResponseBody
{
    [XmlAttribute(AttributeName = "version")]
    public string Version { get; set; }

    [XmlElement(ElementName = "data", Namespace = "Http://example.org/ns1")]
    [MessageBodyMember]
    public SomeOtherType ResponseData { get; set; }
}
like image 93
Andrew Avatar answered Nov 15 '22 10:11

Andrew