Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a SOAP call in C# with an old WSDL+XSD and current Web Service location?

My question is similar to this one: need to call soap ws without wsdl except that my application does not use Spring so the answer was not helpful.

Here's what I have:

  • A web service that only accepts SOAP requests
  • A current endpoint URL for the web service
  • An outdated wsdl and xsd file
  • An outdated sample SOAP request file

What I need to do is:

  • Successfully make a SOAP request using some combination of the above.

I've tried to approach this from two different angles, with no luck so far. My background is familiarity with web services with POST and GETs, but not SOAP. After googling 'C# SOAP', I wrote the following code:

    void soap(String xmlfile)
{
    Stream outputStream = null;
    StreamReader reader = null;
    WebResponse response = null;

    try
    {
        string text = System.IO.File.ReadAllText(xmlfile);

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS");
        request.PreAuthenticate = true;

        X509Certificate ercotCert = X509Certificate.CreateFromCertFile("D:\\Amigo\\WebSite1\\Nodal_Test_Cert.cer");
        request.ClientCertificates.Clear();
        request.ClientCertificates.Add(ercotCert);

        ServicePointManager.ServerCertificateValidationCallback +=
            new System.Net.Security.RemoteCertificateValidationCallback(customValidation);

        request.Credentials = CredentialCache.DefaultNetworkCredentials;

        // I don't actually have a SOAPAction, but have tried adding a fake one just to see
        //request.Headers.Add("SOAPAction", "http://www.ercot.com/Nodal/Payload");

        request.Method = "POST";
        request.ContentType = "text/xml;charset=\"utf-8\"";
        request.ContentLength = text.Length;

        StreamWriter writer = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
        writer.Write(text);
        writer.Close();

        response = request.GetResponse();
        outputStream = response.GetResponseStream();

        reader = new StreamReader(outputStream);
        Response.Write(reader.ReadToEnd());
    }
    catch (WebException e)
    {
        // This is where it ends up, with Status="ProtocolError"
    }
    catch (System.Web.Services.Protocols.SoapException soapE)
    {
        // Never gets in here
    }
    catch (Exception e)
    {
        // Never gets in here
    }
    finally
    {
        if (outputStream != null)
            outputStream.Close();
        if(reader != null)
            reader.Close();
        if(response != null)
            response.Close();
    }
}

private static bool customValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
    return true;
}

This yields a 500 Internal Server Error. It throws a WebException which contains no other message or inner exception, but the Status is 'ProtocolError'. I have tried other permutations including using XmlDocument and other content types, but none have worked.

The other thing I've tried is using "Add Web Reference" in Visual Studio. Putting in the endpoint URL doesn't work and gives a soap fault. If, instead, I point to the local copy of my outdated wsdl, then it will add the WebReference but won't let me use it due to numerous errors that I cannot correct. My guess is that these errors are due to the wsdl being outdated, things like the namespace not matching or being unable to find things at the URLs included. If I replace those URLs with the current web service endpoint URL, it still does not work.

If anyone could pinpoint a problem in my code, or direct me on how to get the "Add Web Reference" working, I would be greatly greatly appreciated!

Thanks in advance!

like image 630
Amber Shah Avatar asked Jan 20 '10 16:01

Amber Shah


People also ask

How do you make SOAP API calls?

Select the Headers tab and add the Content-Type key with the text/xml value. Click on the Body tab, select raw and XML and enter your SOAP message in the input field. That's pretty much it. Afterwards, you should see if your request was successful (hopefully you received a 200 HTTP response).

How do you set a SOAP request header?

Select the service task or web service integration component and click the Variables tab above the diagram area. Create the private variable that you will later map to the SOAP header of the request message. To add a single header entry to the request message, use the variable type SOAPHeader.


1 Answers

SOAP is just the format for the payload that you POST to the service, that's all. There's a defined specification for fields and namespaces and such, and there are different SOAP versions, but there's really not that much to it. (Other than it being remarkably verbose for it's usage, but that's a different topic.)

You need to start with a current WSDL. If you know you're working WSDL is outdated, that means that something the webservice is expecting (required) or could work with (optional) is different from your definition. And the WSDL is your contractual gateway into the webservice. You need to get a current WSDL.

As luck would have it, when I navigate to https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS/?WSDL (which I derived by appending "?WSDL" to the end of the url), after skipping past the certificate error, bingo -- there's the WSDL used by the service. You can either (a) save it locally, or (b) reference it directly from Visual Studio in building a web service client. Because of the cert error, I would recommend saving it locally and building from there.

This should get you started.

like image 159
jro Avatar answered Nov 14 '22 23:11

jro