How to call a web service with no wsdl in .net

51,744

Solution 1

Well, I finally got this to work, so I'll write here the code I'm using. (Remember, .Net 2.0, and no wsdl to get from web service).

First, we create an HttpWebRequest:

public static HttpWebRequest CreateWebRequest(string url)
{
    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
    webRequest.Headers.Add("SOAP:Action");
    webRequest.ContentType = "text/xml;charset=\"utf-8\"";
    webRequest.Accept = "text/xml";
    webRequest.Method = "POST";
    return webRequest;
}

Next, we make a call to the webservice, passing along all values needed. As I'm reading the soap envelope from a xml document, I'll handle the data as a StringDictionary. Should be a better way to do this, but I'll think about this later:

public static XmlDocument ServiceCall(string url, int service, StringDictionary data)
{
    HttpWebRequest request = CreateWebRequest(url);

    XmlDocument soapEnvelopeXml = GetSoapXml(service, data);

    using (Stream stream = request.GetRequestStream())
    {
        soapEnvelopeXml.Save(stream);
    }

    IAsyncResult asyncResult = request.BeginGetResponse(null, null);

    asyncResult.AsyncWaitHandle.WaitOne();

    string soapResult;
    using (WebResponse webResponse = request.EndGetResponse(asyncResult))
    using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
    {
        soapResult = rd.ReadToEnd();
    }

    File.WriteAllText(HttpContext.Current.Server.MapPath("/servicios/" + DateTime.Now.Ticks.ToString() + "assor_r" + service.ToString() + ".xml"), soapResult);

    XmlDocument resp = new XmlDocument();

    resp.LoadXml(soapResult);

    return resp;
}

So, that's all. If anybody thinks that GetSoapXml must be added to the answer, I'll write it down.

Solution 2

In my opinion, there is no excuse for a SOAP web service to not supply a WSDL. It need not be dynamically generated by the service; it need not be available over the Internet. But there must be a WSDL, even if they have to send it to you on a floppy disk thumb drive!

If you have any ability to complain to the providers of this service, then I urge you to do so. If you have the ability to push back, then do so. Ideally, switch service providers, and tell these people it's because they didn't provide a WSDL. At the very least, find out why they don't think it's important.

Solution 3

I have created the following helper method to call WebService manually without any reference:

public static HttpStatusCode CallWebService(string webWebServiceUrl, 
                                            string webServiceNamespace, 
                                            string methodName, 
                                            Dictionary<string, string> parameters, 
                                            out string responseText)
{
    const string soapTemplate = 
@"<?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://www.w3.org/2003/05/soap-envelope"">
  <soap:Body>
    <{0} xmlns=""{1}"">
      {2}    </{0}>
  </soap:Body>
</soap:Envelope>";

    var req = (HttpWebRequest)WebRequest.Create(webWebServiceUrl);
    req.ContentType = "application/soap+xml;";
    req.Method = "POST";

    string parametersText;

    if (parameters != null && parameters.Count > 0)
    {
        var sb = new StringBuilder();
        foreach (var oneParameter in parameters)
            sb.AppendFormat("  <{0}>{1}</{0}>\r\n", oneParameter.Key, oneParameter.Value);

        parametersText = sb.ToString();
    }
    else
    {
        parametersText = "";
    }

    string soapText = string.Format(soapTemplate, methodName, webServiceNamespace, parametersText);


    using (Stream stm = req.GetRequestStream())
    {
        using (var stmw = new StreamWriter(stm))
        {
            stmw.Write(soapText);
        }
    }

    var responseHttpStatusCode = HttpStatusCode.Unused;
    responseText = null;

    using (var response = (HttpWebResponse)req.GetResponse())
    {
        responseHttpStatusCode = response.StatusCode;

        if (responseHttpStatusCode == HttpStatusCode.OK)
        {
            int contentLength = (int)response.ContentLength;

            if (contentLength > 0)
            {
                int readBytes = 0;
                int bytesToRead = contentLength;
                byte[] resultBytes = new byte[contentLength];

                using (var responseStream = response.GetResponseStream())
                {
                    while (bytesToRead > 0)
                    {
                        // Read may return anything from 0 to 10. 
                        int actualBytesRead = responseStream.Read(resultBytes, readBytes, bytesToRead);

                        // The end of the file is reached. 
                        if (actualBytesRead == 0)
                            break;

                        readBytes += actualBytesRead;
                        bytesToRead -= actualBytesRead;
                    }

                    responseText = Encoding.UTF8.GetString(resultBytes);
                    //responseText = Encoding.ASCII.GetString(resultBytes);
                }
            }
        }
    }

    // standard responseText: 
    //<?xml version="1.0" encoding="utf-8"?>
    //<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    //    <soap:Body>
    //        <SayHelloResponse xmlns="http://tempuri.org/">
    //            <SayHelloResult>Hello</SayHelloResult>
    //        </SayHellorResponse>
    //    </soap:Body>
    //</soap:Envelope>
    if (!string.IsNullOrEmpty(responseText))
    {
        string responseElement = methodName + "Result>";
        int pos1 = responseText.IndexOf(responseElement);

        if (pos1 >= 0)
        {
            pos1 += responseElement.Length;
            int pos2 = responseText.IndexOf("</", pos1);

            if (pos2 > pos1)
                responseText = responseText.Substring(pos1, pos2 - pos1);
        }
        else
        {
            responseText = ""; // No result
        }
    }

    return responseHttpStatusCode;
}

You can then simply call any web service method with the following code:

var parameters = new Dictionary<string, string>();
parameters.Add("name", "My Name Here");

string responseText;
var responseStatusCode = CallWebService("http://localhost/TestWebService.asmx", 
                                        "http://tempuri.org/", 
                                        "SayHello", 
                                        parameters, 
                                        out responseText);

Solution 4

If you're lucky you could still get the wsdl. Some web service frameworks allow you to retrieve a dynamically generated WSDL.

Web Services written with Axis1.x allow you to retrieve a dynamically generated WSDL file by browsing to the URL.

Just browse to

http://server/service.soap/?wsdl

I don't know if this is possible with other frameworks though.

Solution 5

Hmm, tricky one here but not impossible but I'll do my best to explian it.

What you'll need to do is

  1. Create serializable classes that match the object schemas you're dealing with on the third party service.
  2. Find out if they use any SOAPAction in their service calls
  3. See if you can create an asmx which mimics their service in terms of being able to handle requests and responses (this will be good for testing your client app if their service is down)
  4. You can then create a service proxy from your dummy service and change the service url when calling the third party service.
  5. If something doesnt work in your client, then you can tweak your dummy service, re-generate the proxy and try again.

I will try to add more as and when I think of it but that should be enough to get you started.

Share:
51,744

Related videos on Youtube

MaLKaV_eS
Author by

MaLKaV_eS

Spanish junior developer.

Updated on July 09, 2022

Comments

  • MaLKaV_eS
    MaLKaV_eS almost 2 years

    I have to connect to a third party web service that provides no wsdl nor asmx. The url of the service is just http://server/service.soap

    I have read this article about raw services calls, but I'm not sure if this is what I'm looking for.

    Also, I've asked for wsdl files, but being told that there are none (and there won't be).

    I'm using C# with .net 2.0, and can't upgrade to 3.5 (so no WCF yet). I think that third party is using java, as that's the example they have supplied.

    Thanks in advance!

    UPDATE Get this response when browsing the url:

    <SOAP-ENV:Envelope>
    <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
    <faultcode>SOAP-ENV:Server</faultcode>
    <faultstring>
    Cannot find a Body tag in the enveloppe
    </faultstring>
    </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    
    • John Saunders
      John Saunders over 14 years
      You should post one or more of the Java example files somewhere, then post the link to them here. One possibility is snipt.org.
    • MaLKaV_eS
      MaLKaV_eS over 14 years
      I've managed to get to connect the webservice, as soon as I have some time I'll post how to do it. Thanks for your interest!
  • Glen
    Glen over 14 years
    thought it was a bit of a long shot. Do you know that framework (if any) the service is written in? If there is no WSDL then how are you supposed to use this service? Do they have any guidelines for you?
  • MaLKaV_eS
    MaLKaV_eS over 14 years
    I'll look for information about this, but please, post any information you think is usefull.
  • MaLKaV_eS
    MaLKaV_eS over 14 years
    They have submited some .java files as example, but as I do know nothing of Java...
  • John Saunders
    John Saunders over 14 years
    Yeah, hope they even have XML schema for this. OTOH, if you're going to do anything with a dummy service, don't do anything with ASMX - use WCF instead.
  • MaLKaV_eS
    MaLKaV_eS over 14 years
    The XML scheme to send and retrieve information are documented. The only thing I lack is the knowledge to connect to it properly. As for the company providing it, is an insurance company, so no possibility to complain :(
  • MaLKaV_eS
    MaLKaV_eS over 14 years
    Is WCF compatible with 2.0? I think it could only be used with 3.0
  • John Saunders
    John Saunders over 14 years
    Actually, I strongly disagree with that. Are these schemas part of any industry-standard, from an industry standards organization (international or not). If so, this gives you a single point to press on, and an industry full of other developers who could join with you in pushing. It's not like you're asking them to do something very complicated or expensive, especially if they already have a mechanism for distributing the schemas. Even if it's specific to the company, once they've got the schemas, the rest is pretty easy.
  • John Saunders
    John Saunders over 14 years
    Sorry, forgot you're stuck in the ancient past. You have to use ASMX, even if Microsoft is no longer fixing bugs in it.
  • John Saunders
    John Saunders over 14 years
    Any luck finding out why they don't want to provide a WSDL? Maybe you should get a trial of XMLspy, and show them how easy it would be, since they've already got the XML schemas.
  • ruedi
    ruedi almost 9 years
    Same problem I get this message: Could not generate WSDL! There is no SOAP service at this location.
  • GuyFawkes
    GuyFawkes about 8 years
    Does not answer the question. Sometimes you have to work with what you got. -1
  • John Saunders
    John Saunders almost 7 years
    @guy and complacency is the reason you'll still have the same problem in a decade.
  • Dave Lawrence
    Dave Lawrence over 6 years
    I'm going to try this - if it works it'll be a mystery to why you've only got the one upvote.
  • Dave Lawrence
    Dave Lawrence over 6 years
    My only neccesary extension to the above would be the inclusion of a SoapHeader..
  • Kiquenet
    Kiquenet over 6 years
    IMHO, I think that GetSoapXml must be added to the answer, Please, you'll write it down
  • MaLKaV_eS
    MaLKaV_eS over 6 years
    As you can see this is a 8 year old question so it's a bit complicated to write GetSoapXml now as I no longer work in the same company, so I don't have access to the code.
  • neminem
    neminem almost 5 years
    In his case, yes, I would've pushed harder. In my case, I'm here because I want to relay an arbitrary request, so I have no reason to care what the request actually looks like, I just want to accept any xml and then pass on that request to a web service after reading the request (one specific request has to be handled differently, and the web service on the other end is a legacy application we can't modify.)
  • tomasofen
    tomasofen over 4 years
    This tío sabe muy day! Thank's sir! ^.^ In my case the URL was: thenameoftheserver/wcf/Service.svc/soap?wsdl