简体   繁体   中英

How to access a PHP Web Service from ASP.Net?

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 functions 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.

Edit:

I tried this piece of code for my 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("foo@mydomain.com", "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.

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/\"><soap:Body>");
            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/">
<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/">
   <SOAP-ENV:Body>
      <ns1:get_contactResponse>
         <get_contactReturn xsi:type="xsd:boolean">false</get_contactReturn>
      </ns1:get_contactResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

"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.

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\">"
            + " <soap:Body soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
            + " <tns:Login>"
            + " <login xsi:type=\"xsd:string\">Support@foo.net</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("Support@foo.net", "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/"><SOAP-ENV:Body><ns1:loginResponse><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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM