views:

717

answers:

4

I am trying use a web service in a C# ASP.Net Web Application. The service is built in php and is located on some remote server not under my control so i cant modify it to add meta data or something else into it.

When i use the "Add Web Reference" option in Visual Studio 2008, I receive the following error:

The HTML document does not contain Web service discovery information.

while trying to add the following web service.

https://subreg.forpsi.com/robot2/subreg_command.php?wsdl

The web service functions are exposed and displayed in Visual Studio 2008. however i could not add the reference to it for use in ASP.Net Application.

t3Service" Description

Methods __construct ( )

create_contact ( )

get_contact ( )

get_domain_info ( )

get_last_error_code ( )

get_last_error_msg ( )

get_NSSET ( )

get_owner_mail ( )

login ( )

register_domain ( )

register_domain_with_admin_contacts ( )

renew_domain ( )

request_sendmail ( )

send_auth_info ( )

transfer_domain ( )

  1. I also tried the wsdl.exe method by retrieving the xml and copying it to a wsdl file and generating a proxy class. But the wsdl output contains warnings and the proxy class generated skips the exposed fucntions and generates something like this:

    // CODEGEN: The operation binding 'create_contact' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_contact' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_domain_info' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_last_error_code' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_last_error_msg' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_NSSET' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'get_owner_mail' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'send_auth_info' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'transfer_domain' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'request_sendmail' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'login' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'register_domain' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'register_domain_with_admin_contacts' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type. // CODEGEN: The operation binding 'renew_domain' from namespace 'urn:t3' was ignored. Each message part in an use=encoded message must specify a type.

Any help in this regard will be highly appreciated.

Regards

Edit:

I tried this piece of code for muy hand coded class.

public String makeWebRequest(String methodName)
        {
              // Create the web request  
              HttpWebRequest request = WebRequest.Create("https://subreg.forpsi.com/robot2/subreg_command.php/") as HttpWebRequest;  
              // Add authentication to request  
              request.Credentials = new NetworkCredential("[email protected]", "bar");
              request.Method = "POST";
              request.ContentType = "text/xml";
              request.Headers.Add("SOAPAction: https://subreg.forpsi.com/robot2/subreg_command.php/" + methodName);

            // Get response  
          using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)  
             {  
               // Get the response stream  
               StreamReader reader = new StreamReader(response.GetResponseStream());  
               // Console application output  
               //Console.WriteLine(reader.ReadToEnd());
               return reader.ReadToEnd();
             }  
        }

But when i try to get response then it returns

The remote server returned an error: (500) Internal Server Error.

Kindly help.

Thanks

+1  A: 

"webservice" is a very generic term. Some types of webservice may implement a WSDL - but its not a requirement. IIRC a SOAP interface is required to provide a WSDL, and both nuSOAP and the PHP SOAP extension support WSDL. So it looks like the remote end hasn't been implemented properly.

symcbean
+1  A: 

As referenced that - you will have to hand code your "proxy" for this web service.

One example of manually making a web service call - you may have to tweak the method some.

private string MakeWebServiceCall(string methodName, string requestXmlString)
        {
            WebRequest webRequest = WebRequest.Create("https://subreg.forpsi.com/robot2/subreg_command.php");

            HttpWebRequest httpRequest = (HttpWebRequest)webRequest;
            httpRequest.Method = "POST";
            httpRequest.ContentType = "text/xml";
            httpRequest.Headers.Add("SOAPAction: https://subreg.forpsi.com/robot2/subreg_command.php/" + methodName);
            Stream requestStream = httpRequest.GetRequestStream();

            //Create Stream and Complete Request
            StreamWriter streamWriter = new StreamWriter(requestStream);
            streamWriter.Write(String.Format(this.GetSoapString(), requestXmlString));
            streamWriter.Close();

            //Get the Response
            WebResponse webResponse = httpRequest.GetResponse();
            Stream responseStream = webResponse.GetResponseStream();
            StreamReader streamReader = new StreamReader(responseStream);

            //Read the response into an xml document
            System.Xml.XmlDocument soapResonseXMLDocument = new System.Xml.XmlDocument();
            soapResonseXMLDocument.LoadXml(streamReader.ReadToEnd());

            //return only the xml representing the response details (inner request)
            return soapResonseXMLDocument.GetElementsByTagName(methodName + "Result")[0].InnerXml;
        }

I would recommend creating xsd's which can be used to generate objects (using xsd.exe) and then you can serialized/deserialize responses and requests to actually objects.

EDIT: GetSoapString() method

private string GetSoapString()
        {
            StringBuilder soapRequest = new StringBuilder("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
            soapRequest.Append(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ");
            soapRequest.Append("xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"&gt;&lt;soap:Body&gt;");
            soapRequest.Append("{0}");
            soapRequest.Append("</soap:Body></soap:Envelope>");
            return soapRequest.ToString();
        }

For Steve's Reference

Call one looks like:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
<soap:Body>
<get_contact>
<id>123</id>
</get_contact>
</soap:Body>
</soap:Envelope>

Response:

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:t3" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&gt;
   <SOAP-ENV:Body>
      <ns1:get_contactResponse>
         <get_contactReturn xsi:type="xsd:boolean">false</get_contactReturn>
      </ns1:get_contactResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Dan
@Dan Thanks a lot for this piece of code. It really cleared my thinking abt the issue. Every thing is quite understandable in your code. But i couldnt get/find the function named *GetSoapString*. Can you please just tell what it does so that i could write one of my own or if it is already defined then could you give it implementation or .Net Namespace that conatins the definition for it???
Steve Johnson
@DanI did try your code. But when try to get a Response from server i receive the following:*The remote server returned an error: (500) Internal Server Error.*Is it normal? If yes then what i need to do in my code to process such a response.Before posting my problem at stackoverflow, i tried some other code and tried to send a web request but the same error was returned.Does it mean that it requires some Authorization or credetials? I clearly see a Login() function there? Is it the SSL thatis creating the problem? If i am to send credentials to the web service how to send them?
Steve Johnson
@Dan* WebResponse webResponse = httpRequest.GetResponse(); *This is the line where the error above is returned..
Steve Johnson
Steve, I'm sorry I forgot to include the GetSoapString - this is one of those utility functions I keep in my bag for the times I have to manually create proxy code.Typically an error 500 comes from a bad header when attempting to make webservice calls...I'll look at that really quick.
Dan
@Steve - I tested this code above and with everything I provided your call should work perfectly. Note: in the last line of the method MakeWebServiceCall the php webservice actually returns a node called methodname+"Response" not methodname+"Result".
Dan
@Dan Thanks a lot for your help. It worked like a charm. Thanks again. :-)
Steve Johnson
A: 

Edit: Previously i got a 500 Internal server error because my soap string was not correctly formatted. I ananlyzed the xml being returned from the web service and built my soap string message by look at xml. Finally i got over the problem with help from Dan ^ & some bit of research over the internet. Thanks Dan.

I got over the 500 server error. Now i am able to get a response of login failure atleast...

public String MyWebServiceCall()
        {
            string strSoapMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
            + "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:tns=\"http://www.artwork-systems.com/webway/sessions\" xmlns:types=\"http://www.artwork-systems.com/webway/sessions/encodedTypes\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"&gt;"
            + " <soap:Body soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"&gt;"
            + " <tns:Login>"
            + " <login xsi:type=\"xsd:string\">[email protected]</login>"
            + " <auth xsi:type=\"xsd:string\">bar</auth>"
            + " </tns:Login>"
            + " </soap:Body>"
            + "</soap:Envelope>";

            HttpWebRequest req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(@"https://subreg.forpsi.com/robot2/subreg_command.php/"));

            req.ContentType = "text/xml; charset=UTF-8";
            req.Method = "POST";
            req.Accept = "text/xml";
            req.Headers.Add("SOAPAction", @"https://subreg.forpsi.com/robot2/subreg_command.php/");
            req.ProtocolVersion = HttpVersion.Version11;
            req.Credentials = CredentialCache.DefaultCredentials;
            //req.Credentials = new NetworkCredential("[email protected]", "bar");

            StreamWriter stm = new StreamWriter(req.GetRequestStream(), Encoding.ASCII);
            stm.Write(strSoapMessage);
            stm.Flush();
            stm.Close();

            HttpWebResponse wr = (HttpWebResponse)req.GetResponse();
            StreamReader srd = new StreamReader(wr.GetResponseStream());
            string resulXmlFromWebService = srd.ReadToEnd();
            return resulXmlFromWebService;
        }

Now the next problem is to pass the correct credentials and process the response to do other stuff...

btw, here was the response....

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:t3" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;&lt;SOAP-ENV:Body&gt;&lt;ns1:loginResponse&gt;&lt;loginReturn xsi:type="xsd:boolean">false</loginReturn></ns1:loginResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

Edit: The value false is Ok as i am sending in the wrong credentials. i call other functions of the web service in a similar fashion and was able to call all functions of the web service and retrieve the corresponding return values and then perform other processing.

Thanks all who helped contributing to solve the problem.

Regards

Steve Johnson
A: 

Hi,

What is requestXmlString in following line

streamWriter.Write(String.Format(this.GetSoapString(), requestXmlString));

node