Search code examples
c#.netwcfsoap

How can I specify a namespace for OperationContract when using WCF?


I am creating a client for a server api I can't change. My client currently produces this format:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <StoreSomething xmlns="urn:aaa">
      <Something>
        <SomeText xmlns="urn:bbb">My text</SomeText>
      </Something>
    </StoreSomething>
  </s:Body>
</s:Envelope>

However, the server expects Something to be in the urn:bbb namespace (i.e. move the xmlns attribute one level up). How can I achieve this? OperationContractAttribute has no Namespace property.

Code:

using System;
using System.ServiceModel;
using System.Xml.Serialization;

[XmlType(Namespace="urn:bbb")]
public class Something
{
    public string SomeText { get; set; }
}

[XmlSerializerFormat]
[ServiceContract(Namespace="urn:aaa")]
public interface IMyService
{
    [OperationContract]
    void StoreSomething(Something Something);
}

class Program
{
    static void Main(string[] args)
    {
        var uri = new Uri("http://localhost/WebService/services/Store");
        var factory = new ChannelFactory<IMyService>(new BasicHttpBinding(), new EndpointAddress(uri));
        IMyService service = factory.CreateChannel();

        service.StoreSomething(new Something
        {
            SomeText = "My text"
        });
    }
}

Solution

  • I managed to get it working by using unwrapped messages. This unfortunately results in both the method name and parameter name being left out. I therefore had to create wrapper classes which results in convoluted code.

    Anyway, here is the code that made it work:

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        [XmlSerializerFormat]
        void StoreSomething(StoreSomethingMessage message);
    }
    
    [MessageContract(IsWrapped=false)]
    public class StoreSomethingMessage
    {
        [MessageBodyMember(Namespace="urn:aaa")]
        public StoreSomething StoreSomething { get; set; }
    }
    
    [XmlType(Namespace="urn:bbb")]
    public class StoreSomething
    {
        public Something Something { get; set; }
    }
    
    public class Something
    {
        public string SomeText { get; set; }
    }
    
    

    I also created a MyServiceClient which implements IMyService and inherits from ClientBase<IMyService> since IMyService now requires a StoreSomethingMessage object, but i left that part out for simplicity.

    I wish there was a simpler solution.