0

Can anyone point me to an example how to post a SOAP Request to a WCF Service and return a SOAP Response? Basically a Travel client sends a SOAP request with search parameters and the WCF Service checks within the database and then sends the appropriate holidays.

I keep getting this error, with the method I have used: "The remote server returned an error: (400) Bad Request"

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kojof
  • 429
  • 7
  • 15
  • 23

5 Answers5

1

The error you got is because the server does not understand the HTTP request. It could be the binding you configured or the service proxy is incorrect at client level.

Or the service you defined expects HTTP GET rather than HTTP POST. Sometimes the add service reference may not generate correct HTTP verb for some [WebGet] attributed operations. You may need to add [WebGet] for the operation at client side manually.

Ray Lu
  • 26,208
  • 12
  • 60
  • 59
1

Either have a look at SoapUI, or locate the WcfTestClient buried deep in your Visual Studio folders (C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE).

Both can connect to a WCF service and send/receive SOAP messages.

Or create your own little client, using svcutil.exe:

svcutil.exe  (service URL)

will create a little *.cs file and a *.config file for you, which you can then use to call the service.

Marc

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
0

You haven't given many details as to how far along you are with the service, so it's hard to say.

If this is literally the first hit to the service, this error could occur if WCF has not been registered properly with IIS. Specifically the .svc extension needs to be mapped to the ASP.NET ISAPI module.

Drew Marsh
  • 33,111
  • 3
  • 82
  • 100
0

thanks for taking the time out to answer this. The service works fine, if a client creates a reference to my WCF Service and makes a method call, the appropriate response is sent.

I forgot to add, that my client is sends a HTTP Post Request to my WCF Service. The appropriate response is then created and returned to the Client.

I can read the HTTP Request, however when i try and access the HTTP response, i get error -"The remote server returned an error: (400) Bad Request"

The error happens when the code reaches this line:

        // Get the response. 
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;

See code below:

 private void CreateMessage()
    {
        // Create a request using a URL that can receive a post. 
        WebRequest request = WebRequest.Create("http://www.XXXX.com/Feeds");
        string postData = "<airport>Heathrow</airport>"; 

// user function request.Method = "POST";

        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        request.ContentType = "application/soap+xml; charset=utf-8";
        request.ContentLength = byteArray.Length;

        Stream dataStream = request.GetRequestStream();
        dataStream.Write(byteArray, 0, byteArray.Length);
        dataStream.Close();

        // Get the response. 
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;

        // Display the status. 
        HttpContext.Current.Response.Write(((HttpWebResponse)response).StatusDescription);

        // Get the stream containing content returned by the server. 
        dataStream = response.GetResponseStream();

        // Open the stream using a StreamReader for easy access. 
        StreamReader reader = new StreamReader(dataStream);

        // Read the content. 
        string responseFromServer = reader.ReadToEnd();

        // Display the content. 
        HttpContext.Current.Response.Write(responseFromServer);

        // Clean up the streams. 
        reader.Close();
        dataStream.Close();
        response.Close(); 

    }

regards

Kojo

Kojof
  • 429
  • 7
  • 15
  • 23
0

Note

The recommended way of accessing WCF Service from other .NET application is by using the "Connected Services" reference. Below I describe how you can create and send SOAP requests in a more manual (and not recommended for production code) manner.

In short

You need:

  • Content-Type: text/xml; charset=utf-8 header
  • SOAPAction: http://tempuri.org/YourServiceClass/YourAction header
  • Request content wrapped in SOAP envelope.

Longer version (example)

Lets take a WCF Service Application scaffolding as an example.

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetData(int value);
}

public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
}

Using Wireshark, I found out that the requests made the default way (connected service reference) contain Content-Type: text/xml; charset=utf-8 and SOAPAction: http://tempuri.org/IService1/GetData headers and following SOAP envelope:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <GetData xmlns="http://tempuri.org/"> <!-- Action name -->
            <value>123</value> <!-- Parameters -->
        </GetData>
    </s:Body>
</s:Envelope>

Using Insomnia, I tested that it's all we need in order to make the request pass successfully, so now just need to port it to the C#:

// netcoreapp3.1
static async Task<string> SendHttpRequest(string serviceUrl, int value)
{
    // Example params:
    //  serviceUrl: "http://localhost:53045/Service1.svc"
    //  value: 123
    using var client = new HttpClient();

    var message = new HttpRequestMessage(HttpMethod.Post, serviceUrl);
    message.Headers.Add("SOAPAction", "http://tempuri.org/IService1/GetData"); // url might need to be wrapped in ""
    var requestContent = @$"
<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body>
    <GetData xmlns=""http://tempuri.org/"">
        <value>{value}</value>
    </GetData>
</s:Body>
</s:Envelope>
";

    message.Content = new StringContent(requestContent, System.Text.Encoding.UTF8, "text/xml");

    var response = await client.SendAsync(message);

    if (!response.IsSuccessStatusCode)
        throw new Exception("Request failed.");

    var responseContent = await response.Content.ReadAsStringAsync();
/*
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
    <GetDataResponse xmlns="http://tempuri.org/">
        <GetDataResult>You entered: {value}</GetDataResult>
    </GetDataResponse>
</s:Body>
</s:Envelope>
*/
    // Just a really ugly regex
    var regex = new Regex(@"(<GetDataResult>)(.*)(<\/GetDataResult>)");
    var responseValue = regex.Match(responseContent).Groups[2].Value;

    return responseValue;
}

You can ofc. use WebClient instead of HttpClient if preferred.

Sebastian
  • 243
  • 2
  • 6