WCF service, response in SOAP or plain XML, how?

29,369

The service you have here will return a SOAP message - which will contain the "CompositeType" as its "payload".

WCF by default uses SOAP - any of the basicHttpBinding, wsHttpBinding, netTcpBinding etc. all work with SOAP as their basis.

If you want to return straight XML, you need to check out the REST capabilities of WCF - this works with the webHttpBinding (and only that binding).

Also, how to produce an XML like this (based on data contract):

<CompositeType BoolValue = 0 StringValue = "">

rather than this:

<CompositeType>
  <BoolValue>0</BoolValue>
  <StringValue></StringValue>
</CompositeType>

This is a limitation of the WCF DataContract serializer. For performance reasons, it does not support attributes, e.g. you cannot create the first fragment of XML that you want.

If you absolutely must have the first XML, you'll need to use the XmlSerializer instead (which has its own set of limitations / problems).

Marc

UPDATE: if you just want to return a given XML, then you're probably better off with the REST approach.

Check out the Pluralsight website for an excellent series of screencasts on using REST and in particular, one screencast on how to create a plain-old XML (POX) REST service.

Share:
29,369
Wodzu
Author by

Wodzu

Judge me based on my activity not my avatar ;-)

Updated on July 30, 2022

Comments

  • Wodzu
    Wodzu almost 2 years

    I am struggling few hours with this and can't find a solution to the communication problem. My service need to communicate with clients via SOAP or plain XML

    My service will be written based on WCF framework, however my clients not.

    Could you show me step by step how to change my service code and configuration in a way that it will return SOAP or XML message? I am interested in both solutions.

    I've tried to achieve this basing on this answers:

    REST / SOAP endpoints for a WCF service Call WCF Using SOAP call

    But none of this solution worked properly for me. Either I got nothing in my browser or error that resource could not be found.

    So I've started a new WCF Service Project. It runs under http://localhost:3151/ and have code like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    namespace WcfService1
    {
        // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
        public class Service1 : IService1
        {
            public string GetData(int value)
            {
                return string.Format("You entered: {0}", value);
            }
    
            public CompositeType GetDataUsingDataContract(CompositeType composite)
            {
                if (composite.BoolValue)
                {
                    composite.StringValue += "Suffix";
                }
                return composite;
            }
        }
    }
    

    Probably I'will need to create two endpoints? Both of them should contain basicHttpBinding as a binding parameter. But what else?

    Also, how to produce an XML like this (based on data contract):

    <CompositeType BoolValue = 0 StringValue = "">
    

    rather than this:

    <CompositeType>
      <BoolValue>0</BoolValue>
      <StringValue></StringValue>
    </CompositeType>
    

    Please note that I need to as a two way communication so my service need to receive SOAP or XML and response in SOAP or XML.

    Also if this is possible I would like to see description of the service methods in my browser just like it was in ASP .NET.

    Thanks in advance for your time.

    Very big update down here

    I've tried to find some solution and here it is all what I gathered so far. I've focused only on plain XML.

    Lets say that the protocol looks like this:

    Message from a client:

    <MESSAGE MessageParam1 = 0>
      <AdditionalInfo>Some message info </AdditionalInfo>
    </MESSAGE>
    

    Response:

    <RESPONSE ResponseParam1 = 0>
      <AdditionalInfo>Some response info</AdditionalInfo>
    </MESSAGE>
    

    First of all, I would like to see description of current service methods and it params in the exact format as they will be send / received. What I mean is that when I was experimented with ASP .NET 2.0 WebServices when I invoked Service in my browser (just started the service) I've got such response:

    POST /Service1.asmx HTTP/1.1
    Host: localhost
    Content-Type: text/xml; charset=utf-8
    Content-Length: length
    SOAPAction: "http://tempuri.org/ShowUser"
    
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
        <ShowUser xmlns="http://tempuri.org/">
          <MyLogin>
            <User>string</User>
            <Password>string</Password>
            <Database>string</Database>
          </MyLogin>
        </ShowUser>
      </soap:Body>
    </soap:Envelope>
    
    HTTP/1.1 200 OK
    Content-Type: text/xml; charset=utf-8
    Content-Length: length
    
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
        <ShowUserResponse xmlns="http://tempuri.org/">
          <ShowUserResult>string</ShowUserResult>
        </ShowUserResponse>
      </soap:Body>
    </soap:Envelope>
    

    And this is GREAT. Apart from that this has SOAP envelope (underlying data is also different) but the point is that I can show it to the client and tell him: "you are doing HTTP POST method with such XML structure and you are receiving such answer". I want similar result with WCF but even simpler - without SOAP. So far, when I click on the Service1.svc I am getting a bunch of WSDL code which I don't want to. I know that this is great for some cases but I don't know what platform is using my client. And if he won't be using .NET than it will probably not import correctly the WSDL.

    So you know what I would like to get.

    This is what I did so far after two long days...:

    namespace RESTService
    {
        // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.
    
        [ServiceContract]
        [XmlSerializerFormat]
        public interface IService
        {
            [OperationContract]
            [WebGet]
            Response EchoWithGet(string s);
    
            [OperationContract]
            [WebInvoke]
            Response EchoWithPost(string s);
        }
    
        public class Response
        {
            [XmlAttribute]
            public int ResponseParam1;
            [XmlElement]
            public string AdditionalInfo;
        }
    }
    

    As you see I did not provide Message class because I don't know how to pass it to the method via browser. I only know how to pass a string.

    And here is the implementation and config:

    namespace RESTService
    {
        // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
        public class Service1 : IService
        {
            public Response EchoWithGet(string s)
            {
                Response Transaction;
                Transaction = new Response();
                Transaction.AdditionalInfo = "I've responded: " + s;
                return Transaction;
            }
            public Response EchoWithPost(string s)
            {
                Response Transaction;
                Transaction = new Response();
                Transaction.AdditionalInfo = "I've responded: " + s;
                return Transaction;
            }
        }
    }
    

    The config is also a bit of mystery for me. I've tried to create binding as it was described in one of the topics from MSDN: http://msdn.microsoft.com/en-us/library/aa395208.aspx

    but then after invoking a method I had returned a SOAP-like fault structure but without SOAP envelope.

    Anyway here is the config:

    <system.serviceModel>
          <services>
             <service name="RESTService.Service1">
               <host>
               </host>
               <endpoint 
                   address="rest" behaviorConfiguration="webBehavior"
                   bindingConfiguration="" binding="webHttpBinding" 
                   contract="RESTService.IService"/>
             </service>
           </services>
           <behaviors>
             <endpointBehaviors>
                <behavior name="webBehavior">
                   <webHttp />
                </behavior>
             </endpointBehaviors>
           </behaviors>
    </system.serviceModel>
    

    When I invoke a service method in my browser like this:

    http://localhost:2443/Service1.svc/rest/EchoWithGet?s=test

    I got in my browser an XML file:

    <Response ResponseParam1="0">
    <AdditionalInfo>I've responded: test</AdditionalInfo>
    </Response>
    

    So it looks like I am on the right track? However still I don't know how to receive a full information (like the one in ASP .NET 2.0 ) about what has been send and what has been received. I would like to rather not listen the service port with sniffer to look what is going through HTTP. I would like to see it. Also, when I look at the source file of the received XML I see this:

    <?xml version="1.0" encoding="utf-8"?><Response ResponseParam1="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br/>
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"><br/>
    <AdditionalInfo>I've responded: test</AdditionalInfo></Response>
    

    I don't want to have this additional info in the returned XML, how to cut this?

    Another problem is with the second method:

    http://localhost:2443/Service1.svc/rest/EchoWithPost?s=test

    This doesn't work as expected. I get the error message that "method is not allowed". How to resolve this?

    So, lets sum up this long question.

    I have some half-working solution which might be the correct way or is the wrong way. I would like to ask you to either finish it that it also could:

    1. Accept in method an XML file as a parameter.
    2. Show me how to call the method in web browser with XML as a parameter. Yes, I don't want to a separate client in .NET. Let the browser will be the client.
    3. Show me how to cut unnecessary bloated info in returned XML.
    4. Show me how to obtain .NET 2.0-like description of my service with bearing on mind that I don't want to have SOAP.
    5. Explain me what is wrong with EchoWithPost method. Why it doesn't work?

    If my example is bad, please provide me some basic example how it should be achieved.

    I am just learning .NET and WCF and I am very confused. All that problems only with setting up correct data exchange protocol... and I even haven't statred to write a real service :|

    Thanks a lot for your time and any future help.

  • Wodzu
    Wodzu over 14 years
    Thanks marc_s but how can I use REST with XMLSerializer? You are saying that to acomplish this simple task I have to abandon the Contracts? Is this possible?
  • marc_s
    marc_s over 14 years
    No - you can still use contracts, but use the XML Serializer instead of the DataContractSerializer, if you really MUST have the format you're looking for. But this will still be a SOAP response.
  • Wodzu
    Wodzu over 14 years
    marc_s: Thank you. The specification doesn't say anything about SOAP. So I guess I need to send and receive just an XML without any envelope. This XML need to have attributes as I have shown it in my question. Can I ask you to show me how to use XMLSerializer? This is 5th hour I am spendig on looking for an answer and I am so frustrated ;)
  • Wodzu
    Wodzu over 14 years
    After second thought: are you saying that I can not send a simple XML with attributes without using SOAP?
  • marc_s
    marc_s over 14 years
    @wodzu: no, you definitely can - if you're using the REST approach, it's totally up to you how to define the response being sent back
  • marc_s
    marc_s over 14 years
    Check out the WCF Rest screencasts at Pluralsight - extremely helpful! pluralsight.com/main/screencasts/default.aspx
  • marc_s
    marc_s over 14 years
    In particular, there's one screencast about creating a "Plain old XML" REST service here: pluralsight.com/main/screencasts/…
  • Wodzu
    Wodzu over 14 years
    Thanks. I will look on the link which you give me. But I am not sure if I really need the REST kit. I don't know if it is free for usage and I was able to do half of the problem without it. Please take a look for my updated question, I think I am almost there?
  • marc_s
    marc_s over 14 years
    @wozdu: yes, you do need the WCF REST starter kit - at least for now. This is the enabling technology allowing you to create plain-old-XML web services - watch the screencast! I say for now since there's a really good chance all this stuff will be rolled into WCF 4.0 that should come out with .NET 4.0/VS2010 before the end of 2009.
  • Wodzu
    Wodzu over 14 years
    @marc but you are saying that I am on the right track and I don't use that kit at all! ;-) But thanks again, I'll look on that webcast tommorow. Hope it will helps...
  • Wodzu
    Wodzu over 14 years
    Thanks Randyaa, will look on that.
  • Wodzu
    Wodzu over 14 years
    @marc I accept this a solution. The link you provided is great but it doesn't show how to return complex XML. So, now I know how to pass complex XML but I don't know how to return it. Situation is reversed...