4

I'm trying to test a WCF service without creating a WCF client. I have similar code/issues as presented here.

I want full control on the SOAP payload so I want to be able to issue my own web requests/responses and substitute my own XML as the parameters into any method. I also want the return SOAP XML exactly as is, without creating response objects, fault exception objects, etc.

As a point of reference, I want to do exactly what SoapUI is doing at the point you click the execute button and get the response back. I'm only assuming that SoapUI is NOT creating a WCF client, building the request and calling the method, but rather issuing a full SOAP call to the WCF service and displaying the result.

In answer to the questions in the comments, the reason I don't want to create a WCF client is that I want to be insulated from any and all changes to the service, not have to rebuild references, modify my own code, create separate code for every new service/method, etc. because this process is kicked off automatically after every build, with no interaction.

So, I have hundreds of thousands of test XML parameters that I pass into hundreds of methods, without caring about what they are. We have done it for years on ASMX web services and the one method (very similar to the above link) handled all web services/methods/test parameters.

With switching to WCF I get internal server errors especially when testing invalid XML nodes: missing required nodes, errors in a create method for duplicate names, etc. (any error condition). I think it makes sense that there is an easy way to do this with WCF in the same manner.

I want EXACTLY what SoapUI is sending back, I just need to know how it's doing it.

Community
  • 1
  • 1
s mac
  • 135
  • 1
  • 1
  • 12
  • I'm not sure what you mean. The call is made by sending the SOAP XML with a POST web request, just like you have said. WCF will take care of the serialization and web request / response level of things. – lockstock May 15 '12 at 23:18
  • @s mac: I suggest you explain what you are trying to do instead of how wou are currently trying. Remove all your comments and instead build a simple, concise question. You mention you are a tester. Do you want to test a WCF web service and want full control on the SOAP payload. Is that it? Why do you want to do it at a low level instead of using a WCF client or SoapUI? – JohnDoDo May 17 '12 at 17:22
  • ok, John...I attempted again. Since I'm not well versed in WCF or SOAP, that's the only way I know how to explain it. I'm sure there is an obvious way to do it (to you and others), I just don't know what it is and I've looked for days. If you have more questions, please let me know. Thanks. – s mac May 17 '12 at 18:49
  • 1
    Whatever you do with ASMX, you should be able to do with WCF. Have you tried it yet? – John Saunders May 17 '12 at 19:05
  • yes...tons of times and a lot of different variations. I have issues when there is some type of error (an error that I tried to create a duplicate item, invalid nodes, etc.) Before with a custom code coming back from the web service, I handled it. Now I just get an internal server error with null coming back and I can't do anything with it. It is worth noting that if I issue the web request and get the reponse back for any call that is valid, everything is fine. It's only when an error condition happens that I can't get a response back. – s mac May 17 '12 at 19:42

2 Answers2

4

@John Saunders is correct in his comment. Whatever you do with ASMX, you should be able to do with WCF. In fact it does not matter what kind of framework/technology your web service uses as long as you do a proper SOAP request.

WCF is just a framework that helps build service-oriented applications. Like any other framework of that kind, it lets you concentrate on the actual service that you will provide, taking care of all the plumbing functionality needed to expose that service as a SOAP web service.

As for SoapUI, its a Java tool that allows you to test web services. When you feed it a WSDL, it dynamically creates request samples which are then sent to the web service with (if I'm not mistaken) Http Client.

Nothing fancy happens if you have a WCF web service. It's still SOAP communication that you can do even with a basic client like this:

public class Program
{
    public static void Main(string[] args)
    {
        // OK, this is not a WCF web service, but that should not matter :D
        string endpoint = "http://www.html2xml.nl/Services/Calculator/Version1/Calculator.asmx";

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endpoint);
        request.ContentType = "text/xml"; // or application/soap+xml for SOAP 1.2
        request.Method = "POST";
        request.KeepAlive = false;

        //In case you have a proxy to resolve the server name also add these lines
        var proxyServer = new WebProxy("XX.XX.XX.XX", 1234);
        proxyServer.Credentials = CredentialCache.DefaultCredentials; // or username + password
        request.Proxy = proxyServer;

        // you can read these from files
        string payload = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:tem=""http://tempuri.org/"">
                               <soapenv:Header/>
                               <soapenv:Body>
                                  <tem:Add>
                                     <tem:a>1</tem:a>
                                     <tem:b>2</tem:b>
                                  </tem:Add>
                               </soapenv:Body>
                            </soapenv:Envelope>";

        byte[] byteArray = Encoding.UTF8.GetBytes(payload);
        request.ContentLength = byteArray.Length;

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

        HttpWebResponse response = null;
        try
        {
             response = (HttpWebResponse)request.GetResponse();
        }
        catch (WebException ex)
        {
             response = (HttpWebResponse)ex.Response;
        }

        Console.WriteLine(string.Format("HTTP/{0} {1} {2}\n", response.ProtocolVersion, (int)response.StatusCode, response.StatusDescription));

        // you can write this to files
        Stream responseStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(responseStream);
        Console.WriteLine(reader.ReadToEnd());

        // cleanp
        reader.Close();
        requestStream.Close();
        responseStream.Close();
        response.Close();
    }
}

You get back a SOAP response, in this case this:

HTTP/1.1 200 OK

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <AddResponse xmlns="http://tempuri.org/">
            <AddResult>3</AddResult>
        </AddResponse>
    </soap:Body>
</soap:Envelope>

and it does not matter if it was an ASMX that generated it, or WCF or whatever. It's the response to a HTTP request.

If instead you send an invalid message, like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Add>
         <tem:a>x</tem:a>
         <tem:b>y</tem:b>
      </tem:Add>
   </soapenv:Body>
</soapenv:Envelope>

you will get back a fault, something like:

HTTP/1.1 500 Internal Server Error

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Client</faultcode>
            <faultstring> ... exception stacktrace here ... </faultstring>
            <detail />
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

You can automate the tests with SoapUI or even integrate them with Junit, you could even use something like JMeter which although not designed specially for web services (like SoapUI) it can test SOAP. And you can off course use that basic client I added to my answer.

Community
  • 1
  • 1
Bogdan
  • 23,890
  • 3
  • 69
  • 61
  • thanks for the response and I agree. It should work the same way. But, it doesn't. Even with your code, I get the same result. If I have a "success" case, it works fine. But, if I get any type of error condition (invalid data, invalid condition, unable to perform the operation for any reason, etc.) I get a (500) - Internal Server Error. I've tried all examples I've seen. Since SoapUI is able to copmlete the calls and return faults within the response, I'm assuming the error is mine somewhere. But, thanks. Even though it didn't solve it for me, it helped my understanding. – s mac May 21 '12 at 15:49
  • @s mac: I added some more details to my answer (mainly the lines before the `Console.WriteLine(string.Format("HTTP/{0} {1} {2}\n" ...`. Tell me if you are now able to get the SOAP fault from the 500 HTTP response. – Bogdan May 21 '12 at 19:54
  • that was exactly my problem. I was typing the answer as you posted this I think. But, yes, thank you. I just didn't know to handle a WebException. – s mac May 21 '12 at 20:05
  • @Bogdan: Can you please suggest where can I find the `soap:envelpe` information for WCF service? Thanks – sarwar026 Mar 11 '14 at 04:55
0

the answer to this was probably obvious to everyone but me...but here it is: I was getting a (500) Internal Server error and didn't know what to do with it. It turns out, again probably obvious to everyone, that you have to catch for a WebException error. The WebException has a Response that you can use to get the fault condition, the full response, etc. I was catching an exception but not specifically for a WebException. Sorry if I confused anyone but I was only having problems when I had error conditions happening, otherwise all the code samples (even my original) were working.

I guess I could post this as another question but is this the typical behavior? Even for an error as simple as trying to create a duplicate record/item, an invalid name, etc. a WebException is thrown? I'm sure due to lack of experience, I was expecting the error response to come back in the same manner as a success response without an internal server error and without needing to catch the WebException outside of the service (except if it truly was a "web" exception).

Thanks for all your answers.

s mac
  • 135
  • 1
  • 1
  • 12
  • 1
    You get the exception whenever the web request cannot be executed successfully. It can be a nuisance sometimes to have to handle an exception but the alternative isn't any better, which is to test for status code 200 after every request. Your code would normally have two execution paths: on success and on failure. An error handler is usually a cleaner way to handle the "on failure" path – Bogdan May 21 '12 at 20:26