1

I need to write a service contract for a very specific SOAP layout (endpoint is not under our control). In essence I need to generate the following soap request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <auth message-id="1">
            <login>
                <UserName>goLocalTeam</UserName>
                <Password>yeay!</Password>
            </login>
        </auth>
    </soapenv:Body>
</soapenv:Envelope>

I have created the following contract:

[ServiceContract(Namespace="", SessionMode=SessionMode.NotAllowed)]
public interface IPrototype
{
    [OperationContract(Action="auth")]
    string auth([MessageParameter(Name = "message-id")]int messageId, Login login);
}

[DataContract(Namespace="")]
public class Login 
{
    [DataMember]
    public string userName { get; set; }
    [DataMember]
    public string Password { get; set; }

}

However, when I construct a client and call, the message-id parameter is rendered as a node inside <auth> instead of being an attribute.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">auth</Action>
  </s:Header>
  <s:Body>
    <auth>
      <message-id>0</message-id>
      <login>
        <userName>yay</userName>
        <Password>yoy</Password>
      </login>
    </auth>
  </s:Body>
</s:Envelope>

Any idea how I can make WCF switch simple-type parameter from node to attribute?

mmix
  • 6,057
  • 3
  • 39
  • 65
  • Action and To headers are not generated my side from wsdl however when I request without these header it throw errors but when i manually add these headers in request it works! however wsdl doesn't have any information of these headers. – Rashmin Javiya Mar 27 '17 at 13:31

2 Answers2

1

Work with the XmlSerializerFormat attribute instead of DataContract.

Take a look at the MSDN to understand exactly how to use it, but basically you mark members with XmlAttribute and XmlElement, so it can look something like:

[ServiceContract(Namespace="", SessionMode=SessionMode.NotAllowed)]
public interface IPrototype
{
    [OperationContract(Action="auth")]
    string Auth(AuthRequest authRequest);
}
[MessageContract(IsWrapped = false)] // notice the unwrapping
public class AuthRequest
{
    [XmlAttribute]
    public int message-id { get; set; }
    [XmlElement]
    public Login Login { get; set; }
}
[MessageContract]
public class Login 
{
    [XmlElement]
    public string userName { get; set; }
    [XmlElement]
    public string Password { get; set; }

}
eladcon
  • 5,815
  • 1
  • 16
  • 19
  • Unfortunately, when I omit '[MessageBodyMember]' the property is not rendered, but when I include it generating a client throws a runtime error: "System.Xml.Serialization.XmlAttributeAttribute is not valid. Only XmlElement, XmlArray, XmlArrayItem, XmlAnyAttribute and XmlAnyElement attributes are supported when IsWrapped is false." I get the same error when I set the IsWrapped to true, only the last word changes, which kind of implies that this is not a solution. – mmix Feb 08 '15 at 18:02
  • Although your answer was not fully correct, it helped show me the way. So I m awarding you points. – mmix Feb 09 '15 at 17:05
1

Ok, I solved it, in part thanks to user3906922, using xml serializer format. I just needed to go a step deeper and fully construct the message:

[ServiceContract(Namespace="", SessionMode=SessionMode.NotAllowed)]
public interface IPrototype
{
    [OperationContract(Action = "auth")]
    [XmlSerializerFormat]
    authResponse auth(authRequest auth);
}

[MessageContract(IsWrapped = false)]
public class authRequest
{
    [MessageBodyMember]
    public authRequestBody auth { get; set; }
}

[MessageContract(IsWrapped = true, WrapperName = "auth")]
public class authRequestBody 
{
    [XmlAttribute(AttributeName = "message-id"), MessageBodyMember]
    public int messageId { get; set; }

    [MessageBodyMember]
    public Login login { get; set; }
}

[MessageContract]
public class Login 
{
    [MessageBodyMember]
    public string userName { get; set; }

    [MessageBodyMember]
    public string Password { get; set; }

}
Community
  • 1
  • 1
mmix
  • 6,057
  • 3
  • 39
  • 65