【问题标题】:How to access a PHP Web Service from ASP.Net?如何从 ASP.Net 访问 PHP Web 服务?
【发布时间】:2013-12-09 20:26:18
【问题描述】:

我正在尝试在 C# ASP.Net Web 应用程序中使用 Web 服务。该服务是用 PHP 构建的,并且位于某个不受我控制的远程服务器上,因此我无法对其进行修改以添加元数据或其他内容。

当我在 Visual Studio 2008 中使用“添加 Web 引用”选项时, 我收到以下错误:

HTML 文档不包含 Web 服务发现信息。

在尝试添加以下 Web 服务时。

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

Web 服务功能在 Visual Studio 2008 中公开和显示。但是我无法添加对它的引用以在 ASP.Net 应用程序中使用。

t3Service" 说明

方法 __构造( )

创建联系人()

get_contact ( )

get_domain_info ( )

get_last_error_code ( )

get_last_error_msg ( )

get_NSSET ( )

get_owner_mail ( )

登录 ( )

注册域()

register_domain_with_admin_contacts ( )

renew_domain ( )

request_sendmail ( )

send_auth_info ( )

transfer_domain ( )

  1. 我还尝试了 wsdl.exe 方法,方法是检索 xml 并将其复制到 wsdl 文件并生成代理类。但是 wsdl 输出包含警告,并且生成的代理类会跳过暴露的函数并生成如下内容:

    // CODEGEN:来自命名空间“urn:t3”的操作绑定“create_contact”被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间“urn:t3”的操作绑定“get_contact”被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'get_domain_info' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'get_last_error_code' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'get_last_error_msg' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'get_NSSET' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'get_owner_mail' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'send_auth_info' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'transfer_domain' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN: 来自命名空间 'urn:t3' 的操作绑定 'request_sendmail' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'login' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'register_domain' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'register_domain_with_admin_contacts' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。 // CODEGEN:来自命名空间 'urn:t3' 的操作绑定 'renew_domain' 被忽略。 use=encoded 消息中的每个消息部分都必须指定一个类型。

编辑:

我为我的手工编码课程尝试了这段代码。

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();
             }  
        }

但是当我尝试得到响应时,它会返回

远程服务器返回错误:(500) Internal Server Error.

【问题讨论】:

    标签: c# php web-services wsdl


    【解决方案1】:

    如前所述 - 您必须为该网络服务手动编写“代理”代码。

    手动进行 Web 服务调用的一个示例 - 您可能需要对方法进行一些调整。

    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;
            }
    

    我建议创建可用于生成对象的 xsd(使用 xsd.exe),然后您可以对实际对象的响应和请求进行序列化/反序列化。

    编辑: GetSoapString() 方法

    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();
            }
    

    供史蒂夫参考

    调用一个看起来像:

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

    回复:

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

    【讨论】:

    • @Dan 非常感谢这段代码。它确实清除了我对这个问题的思考。您的代码中的每一件事都是可以理解的。但我无法获取/找到名为 GetSoapString 的函数。你能告诉我它是做什么的,这样我就可以自己写一个,或者如果它已经定义了,那么你能给它实现或包含它的定义的.Net命名空间吗???
    • @Dan 我确实试过你的代码。但是当尝试从服务器获取响应时,我收到以下信息:远程服务器返回错误:(500)内部服务器错误。正常吗?如果是,那么我需要在我的代码中做什么来处理这样的响应。在 stackoverflow 上发布我的问题之前,我尝试了一些其他代码并尝试发送 Web 请求,但返回了相同的错误。这是否意味着它需要一些授权或凭据?我在那里清楚地看到了一个 Login() 函数?是 SSL 造成的问题吗?如果我要将凭据发送到 Web 服务如何发送它们?
    • @Dan * WebResponse webResponse = httpRequest.GetResponse(); * 这是返回上述错误的那一行..
    • Steve,很抱歉我忘了包含 GetSoapString - 这是我在我必须手动创建代理代码时保留在包中的实用功能之一。通常,在尝试进行 Web 服务调用时,错误 500 来自错误的标头...我会很快查看。
    • @Steve - 我在上面测试了这段代码,并且我提供的所有内容都可以完美运行。注意:在 MakeWebServiceCall 方法的最后一行中,php webservice 实际上返回了一个名为 methodname+"Response" 而不是 methodname+"Result" 的节点。
    【解决方案2】:

    “webservice”是一个非常通用的术语。某些类型的 Web 服务可能会实现 WSDL - 但它不是必需的。 IIRC 需要 SOAP 接口来提供 WSDL,并且 nuSOAP 和 PHP SOAP 扩展都支持 WSDL。所以看起来远端没有正确实现。

    【讨论】:

      【解决方案3】:

      编辑: 以前我收到 500 内部服务器错误,因为我的肥皂字符串格式不正确。我分析了从 Web 服务返回的 xml,并通过查看 xml 构建了我的肥皂字符串消息。 最后,我在 Dan ^ 的帮助下解决了这个问题,并在互联网上进行了一些研究。谢谢丹。

      我解决了 500 服务器错误。现在我 能够得到登录响应 至少失败...

      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;
              }
      

      现在下一个问题是传递正确的凭据并处理响应以执行其他操作...

      顺便说一句,这是回应......

      <?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>
      

      编辑: 值 false 是好的,因为我发送了错误的凭据。我以类似的方式调用 Web 服务的其他函数,并且能够调用 Web 服务的所有函数并检索相应的返回值,然后执行其他处理。

      感谢所有帮助解决问题的人。

      问候

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        相关资源
        最近更新 更多