做这个小程序的时候,看了好多网上的Json解析的方法,主要流行的是使用Newtonsoft.Json类库来实现, 我也下载了并照着做,但是出一些奇怪的报错并不知道怎么解决,然后看了一个Bob Tabor大叔的一节视频,发现讲的简单易懂,实现起来也非常简单,现在就展示一下这种方法(博客最底部有完整源代码)
这里是整个项目文件压缩包的传送门,点击这里
结果展示
1、API选择
- 这里我用的是阿凡达数据,选择的是实现天气预报的接口。
- 进去该网站之后,按照江湖规矩先注册登录,找到想要找的API点击右边的申请数据(一般API都有查询次数的限制,有的还需要付费)
- 然后再返回这个页面就可以看到能够使用了
- 点击申请示例看下得到的数据是什么样纸
2、获取实体类
- 上面能够成功返回Json类型的文本,但是还是不很清楚数据之间的联系,我们用到一个转换Json为C#的网站点这里(别的博客也有推荐一些转换的网站,但是会有问题,比如我这里的Json里面有两个PM25,某些网站就会将这两个类都叫PM25,造成类名重复,后面就很麻烦,而这个网站能够自己加后缀区分相同名称的类)将那些看不懂的数据转换为比较有结构的C#实体类,把上面示例得到的Json文本复制进去点击Generate就好了,就是下面这个样子了
证明一下类名相同的情况
然后呢,直接把得到的C#实体类复制,待会要用
3、实现解析Json返回实体类的方法(?或者叫做函数)
- 到现在还没创建项目,在VS中创建好一个新项目,新建一个类叫做
OpenHistoryToday
,然后在这个类的外面粘贴刚刚得到的实体类
- 可以看到
OpenHistoryToday
中我还写了一个方法叫做GetWeather
,这个就是核心的代码了,现在看看这个怎么写的
public async static Task<RootObject> GetWeather(String city)
{
Uri uri = new Uri(uriString: "http://api.avatardata.cn/Weather/Query?key=0151ec4ce80149ef8ba24b197c36a44f&cityname=" + city);//Uri页面为Json字符串或XML字符串
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
return data;
}
- 因为是异步的方法,所以要用Task修饰,表示在执行查询及解析的过程中返回的数据可能不是RootObject类型,而是一种临时的数据类型,等到数据完全解析成功之后返回RootObject,具体如图(这里的额RootObject是得到数据的最顶层类,认真看看刚刚得到的实体类,需要理清一下关系,应该不难)
- 这里做的工作就是先用数据API的网址创建一个Uri,再创建一个HttpClient并通过异步的方法获取该Uri返回的数据,通过程序集 System.Runtime.Serialization.Json里面的DataContractJsonSerializer类的ReadObject方法返回RootObject类型的变量(还是System自带的程序包好用啊!)
- 对了,直接这样的话有问题,可以发现上面中我的实体类前面加了点东西,因为需要在每个类前面加上Attribute的数据契约关键字([DataContract]),以及在类的成员前面加上[DataMember],这样的话写的方法才能正确识别RootObject类,这是关于C#的特性(Attribute)知识了
4、UI的布置以及输出格式的处理
- 接下来我们再来处理一下button的点击事件,倒不是很难,只要正确理解数据类之间的关系就行了
- 对了还有一点,如果要处理多个API的话,并且他们在同一命名空间下的话就会有类名称的冲突,因为转换得到的都是RootObject,所以要么放在不同命名空间下,要么就更改一下名字
5、完整代码
MainPage.xml
<Page
x:Class="Week7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Week7"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background= "Beige">
<ScrollViewer HorizontalAlignment="Center" Margin="0,0,0,0" Name="scrollViewer1" VerticalAlignment="Center" >
<ScrollViewer.Content>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Name="input" HorizontalAlignment="Center" Margin="0,100,0,0" Width="500" PlaceholderText ="请输入城市名称来查询天气" ></TextBox>
<Button Name="get" HorizontalAlignment="Center" Margin="50,100,0,0" Content="查询天气" Click="Get_ClickAsync" ></Button>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<DatePicker Name="date" YearVisible="False" HorizontalAlignment="Center" Margin="0,50,0,0"></DatePicker>
<Button Name="search" HorizontalAlignment="Center" Margin="50,50,0,0" Content="查询历史上的今天" Click ="search_Click" ></Button>
</StackPanel>
<TextBlock Name="ouput" Margin="0,50,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="18" TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer.Content>
</ScrollViewer>
</Grid>
</Page>
MainPage.xml.cs
using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板
namespace Week7
{
/// <summary>
/// 可用于自身或导航至 Frame 内部的空白页。
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Get_ClickAsync(object sender, RoutedEventArgs e)
{
RootObject myData = await OpenWeatherProxy.GetWeather(input.Text);
if (myData.error_code != 0)
ouput.Text = "城市输入错误,请重新输入!";
else
{
Weather myWeather= myData.result.realtime.weather;
Wind myWind = myData.result.realtime.wind;
String myTime = myData.result.realtime.time;
Pm252 myPm25 = myData.result.pm25.pm25;
List<Weather2> myFutureWeather = myData.result.weather;
ouput.Text = "\n城市:" + myData.result.realtime.city_name +
"\n更新时间:" + myData.result.realtime.date + " " + myTime +
"\n\n天气状况:" + myWeather.info +
"\n温度:" + myWeather.temperature + "℃" +
"\n湿度:" + myWeather.humidity + " %" +
"\n风向:" + myWind.direct +
"\n强度:" + myWind.power + "级" +
"\nPM 2.5:" + myPm25.quality + "( " + myPm25.des + ") " +
"\n\n未来几天天气:" +
"\n * " + myFutureWeather[1].date + " " + myFutureWeather[1].info.day[1] +
"\n * " + myFutureWeather[2].date + " " + myFutureWeather[2].info.day[1] +
"\n * " + myFutureWeather[3].date + " " + myFutureWeather[3].info.day[1] + "\n";
}
}
private async void search_Click(object sender, RoutedEventArgs e)
{
HRootObject myData = await OpenHistoryToday.GetHistory(date.Date.Month, date.Date.Day);
if (myData.error_code != 0)
ouput.Text = "日期选择错误,请重新选择!";
else
{
ouput.Text = "日期 :" + date.Date.Month + " 月 " + date.Date.Day + " 日 " +
"\n * " + myData.result[0].year + "年 " + myData.result[0].title +
"\n * " + myData.result[1].year + "年 " + myData.result[1].title +
"\n * " + myData.result[2].year + "年 " + myData.result[2].title +
"\n * " + myData.result[3].year + "年 " + myData.result[3].title +
"\n * " + myData.result[4].year + "年 " + myData.result[4].title +
"\n * " + myData.result[5].year + "年 " + myData.result[5].title +
"\n * " + myData.result[6].year + "年 " + myData.result[6].title +
"\n * " + myData.result[7].year + "年 " + myData.result[7].title +
"\n * " + myData.result[8].year + "年 " + myData.result[8].title +
"\n * " + myData.result[9].year + "年 " + myData.result[9].title +
"\n * " + myData.result[10].year + "年 " + myData.result[10].title;
}
}
}
}
OpenHistoryToday.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace Week7
{
class OpenHistoryToday
{
public async static Task<HRootObject> GetHistory(int month, int day)
{
Uri uri = new Uri(uriString: "http://api.avatardata.cn/HistoryToday/LookUp?key=5d5d2029b3374020b79af443537b88ee&yue=" + month +" &ri=" + day + "&type=1&page=1&rows=15");
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(HRootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (HRootObject)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class HResult
{
[DataMember]
public int year { get; set; }
[DataMember]
public int month { get; set; }
[DataMember]
public int day { get; set; }
[DataMember]
public string title { get; set; }
[DataMember]
public int type { get; set; }
}
[DataContract]
public class HRootObject
{
[DataMember]
public int total { get; set; }
[DataMember]
public List<HResult> result { get; set; }
[DataMember]
public int error_code { get; set; }
[DataMember]
public string reason { get; set; }
}
}
OpenWeatherProxy.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace Week7
{
class OpenWeatherProxy
{
public async static Task<RootObject> GetWeather(String city)
{
Uri uri = new Uri(uriString: "http://api.avatardata.cn/Weather/Query?key=0151ec4ce80149ef8ba24b197c36a44f&cityname=" + city);//Uri页面为Json字符串或XML字符串
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class Wind
{
[DataMember]
public string windspeed { get; set; }
[DataMember]
public string direct { get; set; }
[DataMember]
public string power { get; set; }
[DataMember]
public string offset { get; set; }
}
[DataContract]
public class Weather
{
[DataMember]
public string humidity { get; set; }
[DataMember]
public string img { get; set; }
[DataMember]
public string info { get; set; }
[DataMember]
public string temperature { get; set; }
}
[DataContract]
public class Realtime
{
[DataMember]
public Wind wind { get; set; }
[DataMember]
public string time { get; set; }
[DataMember]
public Weather weather { get; set; }
[DataMember]
public string dataUptime { get; set; }
[DataMember]
public string date { get; set; }
[DataMember]
public string city_code { get; set; }
[DataMember]
public string city_name { get; set; }
[DataMember]
public string week { get; set; }
[DataMember]
public string moon { get; set; }
}
[DataContract]
public class Info
{
[DataMember]
public List<string> kongtiao { get; set; }
[DataMember]
public List<string> yundong { get; set; }
[DataMember]
public List<string> ziwaixian { get; set; }
[DataMember]
public List<string> ganmao { get; set; }
[DataMember]
public List<string> xiche { get; set; }
[DataMember]
public object wuran { get; set; }
[DataMember]
public List<string> chuanyi { get; set; }
}
[DataContract]
public class Life
{
[DataMember]
public string date { get; set; }
[DataMember]
public Info info { get; set; }
}
[DataContract]
public class Info2
{
[DataMember]
public List<string> dawn { get; set; }
[DataMember]
public List<string> day { get; set; }
[DataMember]
public List<string> night { get; set; }
}
[DataContract]
public class Weather2
{
[DataMember]
public string date { get; set; }
[DataMember]
public string week { get; set; }
[DataMember]
public string nongli { get; set; }
[DataMember]
public Info2 info { get; set; }
}
[DataContract]
public class Pm252
{
[DataMember]
public string curPm { get; set; }
[DataMember]
public string pm25 { get; set; }
[DataMember]
public string pm10 { get; set; }
[DataMember]
public string level { get; set; }
[DataMember]
public string quality { get; set; }
[DataMember]
public string des { get; set; }
}
[DataContract]
public class Pm25
{
[DataMember]
public string key { get; set; }
[DataMember]
public object show_desc { get; set; }
[DataMember]
public Pm252 pm25 { get; set; }
[DataMember]
public string dateTime { get; set; }
[DataMember]
public string cityName { get; set; }
}
[DataContract]
public class Result
{
[DataMember]
public Realtime realtime { get; set; }
[DataMember]
public Life life { get; set; }
[DataMember]
public List<Weather2> weather { get; set; }
[DataMember]
public Pm25 pm25 { get; set; }
[DataMember]
public int isForeign { get; set; }
}
[DataContract]
public class RootObject
{
[DataMember]
public Result result { get; set; }
[DataMember]
public int error_code { get; set; }
[DataMember]
public string reason { get; set; }
}
}
没什么文件结构,就是这个样子