【问题标题】:Consuming a REST XML web service使用 REST XML Web 服务
【发布时间】:2011-06-09 00:37:33
【问题描述】:

我正在尝试使用以下 Web 服务 http://ipinfodb.com/ip_location_api.php 此 Web 服务返回一个 xml 响应,下面的代码获取 XML 响应,但不知何故,当从 XML 响应中调整值时它不起作用。

我的代码有什么问题?

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Net;
using System.Xml;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        HttpWebRequest request = null;
        HttpWebResponse response = null;
        String Xml;

        // Create the web request  
        request = WebRequest.Create("http://api.ipinfodb.com/v2/ip_query.php?key=<yourkey>&ip=74.125.45.100&timezone=true") as HttpWebRequest;

        // Get response  
        using (response = request.GetResponse() as HttpWebResponse)
        {
            // Get the response stream  
            StreamReader reader = new StreamReader(response.GetResponseStream());

            Xml = reader.ReadToEnd();


        }
        // Console xml output  
        Console.WriteLine(Xml); //see if we get the xml response, (YES we do)

        Console.ReadLine();
            string _currentField = "";
            StringReader _sr = new StringReader(Xml);
            XmlTextReader _xtr = new XmlTextReader(_sr);
            _xtr.XmlResolver = null;
            _xtr.WhitespaceHandling = WhitespaceHandling.None;

            // get the root node
            _xtr.Read();

            if ((_xtr.NodeType == XmlNodeType.Element) && (_xtr.Name == "Response"))
            {
                while (_xtr.Read())
                {
                    if ((_xtr.NodeType == XmlNodeType.Element) && (!_xtr.IsEmptyElement))
                    {
                        _currentField = _xtr.Name;
                        _xtr.Read();
                        if (_xtr.NodeType == XmlNodeType.Text)
                        {
                            switch (_currentField)
                            {
                                case "Status":
                                    Console.WriteLine(_xtr.Value); //we print to console for testing purposes, normally assign it to a variable here!
                                    break;
                                case "CountryCode":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "CountryName":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "RegionCode":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "RegionName":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "City":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "ZipPostalCode":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Latitude":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Longitude":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Gmtoffset":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Dstoffset":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "TimezoneName":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Isdst":
                                    Console.WriteLine(_xtr.Value);
                                    break;
                                case "Ip":
                                    Console.WriteLine(_xtr.Value);
                                    break;

                                default:
                                    // unknown field
                                    throw new Exception("Unknown field in response.");
                            }
                        }
                    }
                }
            }
            Console.ReadLine();
    }
}

}

编辑:这是返回的 XML 响应

  <?xml version="1.0" encoding="UTF-8" ?> 
- <Response>
  <Status>OK</Status> 
  <CountryCode>US</CountryCode> 
  <CountryName>United States</CountryName> 
  <RegionCode>06</RegionCode> 
  <RegionName>California</RegionName> 
  <City>Mountain View</City> 
  <ZipPostalCode>94043</ZipPostalCode> 
  <Latitude>37.4192</Latitude> 
  <Longitude>-122.057</Longitude> 
  <Gmtoffset>-28800</Gmtoffset> 
  <Dstoffset>0</Dstoffset> 
  <TimezoneName>America/Los_Angeles</TimezoneName> 
  <Isdst>0</Isdst> 
  <Ip>74.125.45.100</Ip> 
  </Response>

【问题讨论】:

    标签: c# asp.net xml web-services


    【解决方案1】:

    我的解决方案是:

    • 对结果 XML 运行两次 xsd.exe 实用程序,将其转换为 XSD(第一步)和 C# 类(第二步) - 这将为您提供 C# 类 Response

    • 接下来,您可以轻松地将响应反序列化为该类的实例:

      HttpWebRequest request = WebRequest.Create("http://api.ipinfodb.com/v2/ip_query.php?key=--yourkey--&ip=74.125.45.100&timezone=true") as HttpWebRequest;
      
      XmlSerializer ser = new XmlSerializer(typeof(Response));
      
      WebResponse response = request.GetResponse();
      var result = ser.Deserialize(response.GetResponseStream());
      

      现在您的result 将包含Response 的一个实例,所有元素都是对象中的好字段。

    在其MSDN doc page 上阅读有关 xsd.exe 的更多信息。

    【讨论】:

      【解决方案2】:

      我使用相同的 API,我将响应 XML 加载到 XDocument 并解析例如

      // build URL up at runtime
      string apiKey = ConfigurationManager.AppSettings["geoApiKey"];
      string url = String.Format(ConfigurationManager.AppSettings["geoApiUrl"], apiKey, ip);
      
      WebRequest request = WebRequest.Create(url);
      try
      {
          WebResponse response = request.GetResponse();
          using (var sr = new System.IO.StreamReader(response.GetResponseStream()))
          {
              XDocument xmlDoc = new XDocument();
              try
              {
                  xmlDoc = XDocument.Parse(sr.ReadToEnd());
                  string status = xmlDoc.Root.Element("Status").Value;
                  Console.WriteLine("Response status: {0}", status);
                  if (status == "OK")
                  { 
                      // if the status is OK it's normally safe to assume the required elements
                      // are there. However, if you want to be safe you can always check the element
                      // exists before retrieving the value
                      Console.WriteLine(xmlDoc.Root.Element("CountryCode").Value);
                      Console.WriteLine(xmlDoc.Root.Element("CountryName").Value);
                      ...
                  }                
              }
              catch (Exception)
              {
                  // handle if necessary
              }   
          }
      }
      catch (WebException)
      {
          // handle if necessary    
      }
      

      您还应该做的是引入一个自定义类,例如GeoLocationInfo 并将您的代码包装在一个函数中,例如GetGeoLocation(string ip) 然后,您可以填充并返回该类的实例,而不是将信息写入控制台窗口。

      【讨论】:

        【解决方案3】:

        您假设第一个节点将是根节点,但这是不正确的。您将首先拥有XmlDeclaration 节点,然后可能是Whitespace 节点。所以你可能应该像

        这样来构建你的代码
        ...
        bool isRootRead = false;
        while (_xtr.Read())
        {
            if (_xtr.NodeType == XmlNodeType.Element)
            {
                if (!isRootRead)
                {
                    if (_xter.Name == "Response")
                    {
                        // root found
                        isRootRead = true;
                    }
                    // jump to next node if root node / ignore other nodes till root element is read
                    continue;
                }
                _currentField = _xtr.Name;
                _xtr.Read();
                if (_xtr.NodeType == XmlNodeType.Text)
                {
                    switch (_currentField)
                    {
                        case "Status":
                            Console.WriteLine(_xtr.Value); //we print to console for testing purposes, normally assign it to a variable here!
                            break;
        ...
        

        但说了这么多,我个人更喜欢创建响应 XSD(如果 Web 服务提供它会更好)并从中生成类(使用 XSD.exe 或 Xsd2Code)以对其进行序列化/反序列化。

        【讨论】:

          【解决方案4】:

          我认为您需要使用 _xtr.MoveToContent();使用read方法之前的方法.. 看看有没有用

          【讨论】:

            猜你喜欢
            • 2014-02-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-06
            相关资源
            最近更新 更多