简体   繁体   中英

How to send xml via post to wcf service

I got a code which post xml to wcf service. Here is the full code

1) WCF Service Interface

[OperationContract]
[WebInvoke(Method = "POST",
    UriTemplate = "GetData",
    RequestFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Bare)]
string GetData(DataRequest parameter);

2) WCF Service Implementation

public string GetData(DataRequest parameter)
{
    //Do stuff
    return "your data here";
}

3) Data Contract in your WCF service (In this case it's DataRequest)

[DataContract(Namespace = "YourNamespaceHere")]
public class DataRequest
{
    [DataMember]
    public string ID{ get; set; }
    [DataMember]
    public string Data{ get; set; }
}

4) Client sending the data must have the data constructed properly! (C# console app in this case)

static void Main(string[] args)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    string SampleXml = "<DataRequest xmlns=\"YourNamespaceHere\">" +
                                    "<ID>" +
                                    yourIDVariable +
                                    "</ID>" +
                                    "<Data>" +
                                    yourDataVariable +
                                    "</Data>" +
                                "</DataRequest>";

    string postData = SampleXml.ToString();
    byte[] data = encoding.GetBytes(postData);

    string url = "http://localhost:62810/MyService.svc/GetData";

    string strResult = string.Empty;

    // declare httpwebrequet wrt url defined above
    HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
    // set method as post
    webrequest.Method = "POST";
    // set content type
    webrequest.ContentType = "application/xml";
    // set content length
    webrequest.ContentLength = data.Length;
    // get stream data out of webrequest object
    Stream newStream = webrequest.GetRequestStream();
    newStream.Write(data, 0, data.Length);
    newStream.Close();

    //Gets the response
    WebResponse response = webrequest.GetResponse();
    //Writes the Response
    Stream responseStream = response.GetResponseStream();

    StreamReader sr = new StreamReader(responseStream);
    string s = sr.ReadToEnd();

    return s;
}

My question is that if GetData() function expect two or more parameter then how could I supply value to GetData()

public string GetData(string xml1,string xml2)
{
     //Do stuff return "your data here";
}

so please guide me how to pass two xml data to GetData() function ?

First of all you can't have a service with WebMessageBodyStyle.Bare and a method that takes two parameters. You'll need to change to a WrappedRequest as a minimum:

[OperationContract]
[WebInvoke(Method = "POST",
     UriTemplate = "GetData",
     RequestFormat = WebMessageFormat.Xml,
     BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetData(DataRequest xml1, string xml2);

With that out of the way let's see what the wire format needs to be for this webHttp binding.

The root element needs to be named as the name of the operation, GetData . Next are a sequence of child elements, for each parameter one. The default name of those elements equals the name of your variable, so in the example it would be xml1 and xml2 . Those defaults can be influenced by decorating the parameter with a [MessageParameter(Name="Bar")] attribute.

Applying above ground rules would require that your HTTP Post body looks similar to this:

<GetData>    <!-- Operation -->
    <xml1>   <!-- parameter one -->
    </xml1>
    <xml2>   <!-- parameter two -->
    </xml2>
</GetData>

Unfortunately this is not it. The service and it's contracts have namespace. Without any decoration the namespace is the ugly http://tempuri.org/ which I replaced on the IService interface with

 [ServiceContract(Namespace="http://service.stackoverflow.com")]

In your first example the DataRequest type had a namespace. In my test I decorated the type with

 [DataContract(Namespace="http://data.stackoverflow.com")]

Now we need to add those namespaces (with namespace aliases) to our basic xml payload:

<GetData xmlns="http://service.stackoverflow.com"> <!-- Operation with default namespace  -->
    <xml1 xmlns:a="http://data.stackoverflow.com">   <!-- namespace on type -->
      <a:ID>42</a:ID> <!-- members are in the type namespace, use the alias --> 
      <a:Data>FuBar</a:Data> 
    </xml1>
    <xml2>   <!-- parameter two, no explicit namespace so is in the default one -->
       BlahBlah
    </xml2>
</GetData>

Posting that payload to the service at Service1.svc/GetData does invoke the service with the parameters having the deserialized data.

To answer your question exactly given your example code change at the Service:

[ServiceContract(Namespace="http://service.stackoverflow.com")]
public interface IService1
{
    [OperationContract]
    [WebInvoke(Method = "POST",
      UriTemplate = "GetData",
        RequestFormat = WebMessageFormat.Xml,
        BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    string GetData([MessageParameter(Name="Bar")] DataRequest xml1, string xml2);
}

and at the client:

var yourIDVariable = "foo";
var yourDataVariable = "bar";
string SampleXml = "<xml1 xmlns:a=\"http://data.stackoverflow.com\">" +
                                "<a:ID>" +
                                yourIDVariable +
                                "</a:ID>" +
                                "<a:Data>" +
                                yourDataVariable +
                                "</a:Data>" +
                            "</xml1>";

string xml2 = "some data";
string wrapper = "<GetData xmlns=\"http://service.stackoverflow.com\">{0}<xml2>{1}</xml2></GetData>";
string postData = String.Format(wrapper, SampleXml, xml2);

When dealing with WCF service call and diagnosing serialization issues it is extremely convenient to enable WCF message logging in the config of system.serviceModel :

<diagnostics>
  <endToEndTracing activityTracing="true" messageFlowTracing="true" propagateActivity="true"/>
  <messageLogging
     logKnownPii="true"
     logEntireMessage="true" 
     logMalformedMessages="true"
     logMessagesAtServiceLevel="true" 
     logMessagesAtTransportLevel="true"
     maxMessagesToLog="30000"
     maxSizeOfMessageToLog="20000"/>
</diagnostics> 

and the suitable listener:

<system.diagnostics>
   <sources>
     <source name="System.ServiceModel.MessageLogging">
       <listeners>
             <add name="messages"
             type="System.Diagnostics.XmlWriterTraceListener"
             initializeData="messages.svclog" />
        </listeners>
     </source>
  </sources>
  <trace autoflush="true"></trace>
</system.diagnostics>

Which gives you the exact payload in the Service Trace Viewer :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM