Получение данных с сервера в json

Последнее обновление: 19.08.2016

Одним из ключевых моментов работы многих мобильных приложений является возможность взаимодействия с сервером - отправка или получение данных. И в Xamarin Forms мы тоже можем взаимодействовать с сервером. Рассмотрим на примере получения данных в формате json.

В качестве примера возьмем бесплатный API от Yahoo для получения текущих котировок валют. Так, для получения текущих значений для пары "рубль-доллар" в данном API необходимо обратиться по адресу https://query.yahooapis.com/v1/public/yql?q=select+*+from+yahoo.finance.xchange+where+pair+=+%22USDRUB%22&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=. И в качестве ответа мы получим данные в формате json примерно следующего вида:

{
	"query":{
		"count":1,
		"created":"2016-08-19T15:46:31Z",
		"lang":"ru-RU",
		"results":{
			"rate":{
				"id":"USDRUB",
				"Name":"USD/RUB",
				"Rate":"64.0425",
				"Date":"8/19/2016",
				"Time":"12:53pm",
				"Ask":"64.0513",
				"Bid":"64.0425"
			}
		}
	}
}

Теперь посмотрим, как мы эти данные можем получать и отображать в приложении на Xamarin Forms.

Создадим новый проект и вначале добавим в него класс, который будет представлять загружаемые данные. Назовем этот класс RateInfo:

using System;
namespace RestApp
{
    public class RateInfo
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public decimal Rate { get; set; }
        public DateTime Date { get; set; }
        public string Time { get; set; }
        public decimal Ask { get; set; }
        public decimal Bid { get; set; }
    }
}

Как можно заметить, данный класс соответствует части ответа от сервера в формате json:

"rate":{
	"id":"USDRUB",
	"Name":"USD/RUB",
	"Rate":"64.0425",
	"Date":"8/19/2016",
	"Time":"12:53pm",
	"Ask":"64.0513",
	"Bid":"64.0425"
}

Затем поскольку мы загружаем данные в формате json, то нам надо будет десериализовать эти данные. Для этого будем использовать библиотеку Newtonsoft.Json, которую добавим в проект через Nuget:

Newtonsoft.Json в Xamarin Forms

Далее добавим в проект класс RateViewModel, который будет представлять ViewModel, через которую будет идти загрузка и отображение данных на странице:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.ComponentModel;
using System.Net.Http;
using System.Windows.Input;
using Xamarin.Forms;

namespace RestApp
{
    public class RateViewModel : INotifyPropertyChanged
    {
        private decimal rate;
        private decimal ask;
        private decimal bid;

        public decimal Rate
        {
            get { return rate; }
            private set
            {
                rate = value;
                OnPropertyChanged("Rate");
            }
        }
       
        public decimal Ask
        {
            get { return ask; }
            private set
            {
                ask = value;
                OnPropertyChanged("Ask");
            }
        }
        public decimal Bid
        {
            get { return bid; }
            private set
            {
                bid = value;
                OnPropertyChanged("Bid");
            }
        }

        public ICommand LoadDataCommand { protected set; get; }

        public RateViewModel()
        {
            this.LoadDataCommand = new Command(LoadData);
        }

        private async void LoadData()
        {
            string url = "https://query.yahooapis.com/v1/public/yql?q=select+*+from+yahoo.finance.xchange+where+pair+=+%22USDRUB%22&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=";

            try
            {
                HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(url);
                var response = await client.GetAsync(client.BaseAddress);
                response.EnsureSuccessStatusCode(); // выброс исключения, если произошла ошибка

                // десериализация ответа в формате json
                var content = await response.Content.ReadAsStringAsync();
                JObject o = JObject.Parse(content);

                var str = o.SelectToken(@"$.query.results.rate");
                var rateInfo = JsonConvert.DeserializeObject<RateInfo>(str.ToString());

                this.Rate = rateInfo.Rate;
                this.Ask = rateInfo.Ask;
                this.Bid = rateInfo.Bid;
            }
            catch(Exception ex)
            { }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string prop = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}

Прежде всего надо отметить, что данный класс реализует интерфейс INotifyPropertyChanged. В классе определены свойства Rate, Bid, Ask, которые аналогичны соответствующим свойствам из класса Rate и данные которых будут выводиться на страницу.

Для загрузки данных определено свойство-команда LoadDataCommand. Эта команда при выполнении будет вызывать метод LoadData().

Для взаимодействия с сервером применяется класс HttpClient. Он определяет ряд методов, через которые можно отправлять серверу данные или, наоборот, получать от него данные. В данном случае мы задействует метод client.GetAsync() для получения ответа по указанному адресу.

С помощью метода response.EnsureSuccessStatusCode() указываем, что в случае неудачного выполнения запроса будет выброшено исключение, которое мы можем обработать.

В итоге весь код загрузки данных по определенному адресу выглядеть следующим образом:

HttpClient client = new HttpClient();
client.BaseAddress = new Uri(url);
var response = await client.GetAsync(client.BaseAddress);
response.EnsureSuccessStatusCode(); // выброс исключения, если произошла ошибка

После получения ответа его надо привести в тот вид, который позволит нам манипулировать содержащимися в нем данными. Для этого вначале получим текст ответа с помощью метода response.Content.ReadAsStringAsync().

Поскольку текст ответа представляет данные в формате json, то нам их надо распарсить и привести к объекту RateInfo. Для этого получаем JObject для упрощения работы с данными:

JObject o = JObject.Parse(content);

Поскольку нас интересуют не все абсолютно данные, а только их часть (элемент rate в полученном ответе), то нам их надо извлечь:

var str = o.SelectToken(@"$.query.results.rate");

Выражение "$.query.results.rate" представляет синтаксис языка запросов в JSON - JsonPath, с помощью которого мы можем обратиться к определенной порции данных. В данном случае мы получаем узел rate, который находится в узле results, который в свою очередь находится в узле query. То есть по факту мы получим следующий узел:

"rate":{
	"id":"USDRUB",
	"Name":"USD/RUB",
	"Rate":"64.0425",
	"Date":"8/19/2016",
	"Time":"12:53pm",
	"Ask":"64.0513",
	"Bid":"64.0425"
}

И в конце десериализуем этот узел в объект RateInfo (десериализация идет на основании соответствия свойств класса и свойств в json):

JsonConvert.DeserializeObject<RateInfo>(str.ToString())

После этого происходит установка полученных данных:

this.Rate = rateInfo.Rate;
this.Ask = rateInfo.Ask;
this.Bid = rateInfo.Bid;

И в конце определим главную страницу MainPage. В коде C# определим в качестве контекста страницы объект RateViewModel:

using Xamarin.Forms;

namespace RestApp
{
    public partial class MainPage : ContentPage
    {
        RateViewModel viewModel;
        public MainPage()
        {
            InitializeComponent();

            viewModel = new RateViewModel();
            // установка контекста данных
            this.BindingContext = viewModel;
        }
    }
}

А в коде XAML определим привязку элементов к свойствам RateViewModel:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="RestApp.MainPage">
  <StackLayout>
    <Button Text="Получить курс" Command="{Binding LoadDataCommand}"  />
    <Label FontSize="Medium" Text="Текущий курс" />
    <Label FontSize="Medium" FontAttributes="Bold" Text="{Binding Rate}" />
    <Label FontSize="Medium" Text="Спрос" />
    <Label FontSize="Medium" FontAttributes="Bold"  Text="{Binding Ask}" />
    <Label FontSize="Medium" Text="Предложение" />
    <Label FontSize="Medium" FontAttributes="Bold" Text="{Binding Bid}" />
  </StackLayout>

</ContentPage>

Запустим приложение и нажмем на кнопку, и на странице отобразятся загруженные с сервера данные:

Загрузка данных в json в Xamarin Forms
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850