четверг, 27 января 2011 г.

EasyHTTP – инструмент для удобного взаимодействия с веб-сервером

Работая над множеством интернет-проектов, я довольно часто сталкиваюсь с проблемой, когда приходится обмениваться данными с сервером не посредстовом вызова веб-сервисов, а непосредственно создавая и отправляя HtppRequest с прикрепленными параметрами и обрабатывая HttpResponse, приводя возвращенные данные к нужному объекту класса.

Конечно же, если я разработчик и клиентской и серверной части приложения, то для более удобного обмена данными создаю необходимые мне веб-сервисы, а на клиенте с помощью встроенных механизмов VisualStudio парой кликов мыши легко генерирую proxy-классы для получения и отправки нужных мне объектов.В итоге на клиент я получаю сразу объекты нужных мне классов, без необходимости парсинга ответа сервера.

Можно продемонстрировать коротенький пример данного подхода: допустим мы имеем обычный RSS-клиент, но оперирующий данными, хранящимися на сервере. Наш клиент может получать список новых статей, добавлять новый RSS-канал, отмечать статьи как прочитанные.

Для удобного оперирования данными создадим соответвующие классы объектов приложения:

public class RssChanel
{
public int Id { get; set; }
public string Title { get; set; }
public string RssUrl { get; set; }
public string Category { get; set; }
}

public class SitePage
{
public int Id { get; set; }
public int RssChanelId { get; set; }
public RssChanel RssChanelSource { get; set; }
public string Title { get; set; }
public string Preview { get; set; }
public string Url { get; set; }
public DateTime CreateDate { get; set; }
public bool IsRead { get; set; }
}



Далее создаем CRUD-методы для получения, удаления, сохранения данных в хранилище. Ну а чтобы не усложнять себе работу в создании клиентского приложения, создаем веб-сервис для взаимодействия с данным веб-приложением и реализовуем перечисленные выше методы, необходимые нашему клиентскому приложению: получение данных, добавление нового канала, редактирование страницы (пометить как прочитанная).


/// <summary>
/// Summary description for RssService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class RssService : System.Web.Services.WebService
{

[WebMethod]
public bool RssChanelProvider_Insert(RssChanel chanel)
{
return DataRepository.RssChanelProvider.Insert(chanel);
}

[WebMethod]
public bool RssChanelProvider_Update(RssChanel chanel)
{
return DataRepository.RssChanelProvider.Update(chanel);
}

[WebMethod]
public bool RssChanelProvider_Delete(int chanelId)
{
return DataRepository.RssChanelProvider.Delete(chanelId);
}

[WebMethod]
public SitePage[] SitePageProvider_GetAll(int pageLength)
{
return DataRepository.SitePageProvider.GetAll(pageLength).ToArray();
}

[WebMethod]
public bool SitePageProvider_Update(SitePage sitePage)
{
return DataRepository.SitePageProvider.Update();
}
}


Итак, теперь с помощью соответсвующих запросов мы можем достучаться до методов нашего веб-сервиса


image


Теперь приступим к релазации клиентского приложения. С помощью встроенных механизмов генерации прокси-класов для вызова методов веб-сервиса, достучаться до нашего сервиса не составляет особого труда.


image


image


Все. Далее всю сложную работу по созданию прокси-класов, wsdl-описания сервиса и многое другое берет на себя VisualStudio. Также в конфигурационный файл добавляется сексия управления каналом связи с сервером. Тонна рутинной работы была сделана за нас студией. Нам же остается лишь изменить тестовый URL-адрес сервера на реальный.


В итоге мы имеем удобную объектную модель для обмена данными с сервером.


image image


Следующий код будет абсолютно валидным и компилируемым:


static void Main(string[] args)
{
RssServiceSoapClient serviceClient = new RssServiceSoapClient();

SitePage[] sitePages = serviceClient.SitePageProvider_GetAll(20);

foreach (SitePage sitePage in sitePages)
{
sitePage.IsRead = true;
serviceClient.SitePageProvider_Update(sitePage);
}
}






Отлично. Если же наше веб-приложение постоянно развивается и объектная модель со временем может менятся – для клиента необходимо просто перегенерировать ServiceReference и новые свойства будут доступны в перегенерированных proxy-классах.


image


В итоге без особых сложностей мы можем делать клиент-серверные приложения, оперируя при этом единым набором объектов классов, без необходимости писать свои конверторы для анализа ответа сервера.


Хорошо, но что делать, если необходимо создать клиентское приложение, получающее и обрабатывающее данные не с нашего сервера, т.е. где мы не можем гарантировать, что обмен данными происходит через веб-сервисы.


К тому же мы не можетvгарантировать, что все ресурсы, из которых мы чарпаем данные, отдают нам их именно в том формате, в котором нам надо. Хотелось бы иметь какое-то универсальное средство, упрощающее монотонную работу с HTTP – Get,Post,Delete,Put, сериализация из JSON в объектную модель приложения, чтение данных из REST-full сервисов.


Анализируя библиотеки сторонных разработчиков, я нашел для себя наиболее удобную – EsayHTTP. Можно на первом коротеньком примере показать, в чем именно упрощается работа при использовании данной библиотеки:


var http = new HttpClient
{
Request = {Accept = HttpContentTypes.ApplicationJson}
};

var response = http.Get("http://domain.com/customer/25");

var customer = response.StaticBody<Customer>();



Буквально несколько строчек кода и сразу экономия нескольких часов рутинной работы: создания helper-классов для отправки запросов и получения ответов сервера, создание helper-классов для десеаризилицации ответов и многое другое.


В этом же примере мы задаем Accept Header возвращаемой страницы и конвертируем ответ в strogly-typed объект Customer.


Если же наша бизнес-модель не имеет точного типа объекта для десериализации ответа сервера, мы может проделать следующие манипуляции:


var http = new HttpClient
{
Request = {Accept = HttpContentTypes.ApplicationJson}
};

var response = http.Get("http://domain.com/customer/25");

dynamic customer = response.DynamicBody();

Console.WriteLine(customer.Name);
Console.WriteLine(customer.Email);



В этом случае мы хотим возвратить динамический тип, чтобы десериализовать ответ в динамический объект. Это дает нам возможность выбирать лишь необходимые нам значения полей из объекта, не создавая для этогого отдельные классы.


Если же нам просто надо скачать страницу или изображение и сохранить его в файл на локальном компьюетере:


var http = new HttpClient();
http.GetAsFile("http://ydobno.net/logo.png", @"C:\Logos\ydobno\logo.png");


Крайне просто также сделать POST-запрос на сервер:


var http = new HttpClient();

var customer = new Customer()
{
Name = "Joe Smith",
Email = "Joe@Gmail.com"
};

http.Post("http://domain.com/customer", customer, HttpContentTypes.ApplicationJson);



К тому же мы можем задавать тип кодировки передаваемых данных, в нашем случае данные на сервере принимаются в формате JSON.


Отлично. Благодаря данной библиотеке мы сразу получили мощный инструмент для взаимодействия с удаленным сервером, получили возможность обрабатывать и посылать запросы, не погружаясь в глубины HTTP, получили возможность вытягивать из ответного потока объекты, не погружаясь в глубины десеарилизации. Конечно же, данная библиотека не является панацеей от всех проблем и скорее всего придется делать свои классы для работы с сервером на уровне HTTP, но во многих стандартных вопросах смело можно положится именно на нее.

Комментариев нет:

Отправить комментарий