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 ( )
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 开发者_StackOverflow社区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
精彩评论