С выходом Windows Phone 8.1 появилась новая возможность в разработке приложений магазина Windows / Windows phone с общей кодовой базой. Это так называемые универсальные приложения, базирующиеся на более общем API и возможности повторного использования разметки XAML в Visual Studio 2013 сразу из коробки.
Если приложение магазина Windows использует WCF для работы с SOAP сервисами, то попытка портирования на Windows phone может завершиться неудачей. Как оказалось, пространство имен System.ServiceModel отныне недоступно. Соответственно требуется замена, отвечающая следующим требованиям:
SOAP запрос представляет собой особым образом сформированный XML документ. Все что необходимо сделать это сериализовать данные запроса в XML, поместить их в элемент Body и отправить в теле HTTP POST запроса. Структура ответа аналогична, результат получается из элемента Body.
На основе HttpClient реализуем базовый класс для формирования запроса. В результате получаем функцию следующего вида:
Остается только подставить соответствующие классы TRequest и TResponse которые можно получить на основе описания сервиса. SOAP сервисы описываются при помощи Web Services Description Language (WSDL), языка, описывающего API сервиса в виде операций и типов данных.
К получению информации о сервисе можно подойти с разных сторон:
Исходный код полученный при помощи SvcUtil не может напрямую использоваться для приложений магазина Windows Phone по причине наличия следующих не поддерживаемых конструкций:
Если приложение магазина Windows использует WCF для работы с SOAP сервисами, то попытка портирования на Windows phone может завершиться неудачей. Как оказалось, пространство имен System.ServiceModel отныне недоступно. Соответственно требуется замена, отвечающая следующим требованиям:
- Простота использования, аналогично старому Add Service Reference, где на выходе получается сгенерированный код строго типизированного клиента сервиса;
- Расширяемость, как показала практика может потребоваться поддержка различных схем аутентификации.
SOAP запрос представляет собой особым образом сформированный XML документ. Все что необходимо сделать это сериализовать данные запроса в XML, поместить их в элемент Body и отправить в теле HTTP POST запроса. Структура ответа аналогична, результат получается из элемента Body.
На основе HttpClient реализуем базовый класс для формирования запроса. В результате получаем функцию следующего вида:
public async Task<TResponse> CallAsync<TRequest, TResponse>(string action, TRequest request)
{
IHttpContent httpContent = GetHttpContent(action, request);
var response = await Client.PostAsync(EndpointAddress, httpContent);
var responseContent = await response.Content.ReadAsStringAsync();
return GetResponse<TResponse>(responseContent);
}
Остается только подставить соответствующие классы TRequest и TResponse которые можно получить на основе описания сервиса. SOAP сервисы описываются при помощи Web Services Description Language (WSDL), языка, описывающего API сервиса в виде операций и типов данных.
К получению информации о сервисе можно подойти с разных сторон:
- Работа с сырым WSDL. Можно, но для поставленной задачи слишком трудоемко, пойдем лучше по пути наименьшего сопротивления;
- Использовать класс System.ServiceModel.Description.MetadataExchangeClient, это самый разумный вариант, однако реализация этого класса не позволяет работать с любым WSDL. Если в документе содержится элемент import, то MetadataExchangeClient вываливается с ошибкой;
- Использовать консольную утилиту SvcUtil входящую в состав .Net Framework SDK. На выходе мы получим тот же исходный код что и при использовании Add Service Reference из Visual Studio, который и возьмем за основу.
Исходный код полученный при помощи SvcUtil не может напрямую использоваться для приложений магазина Windows Phone по причине наличия следующих не поддерживаемых конструкций:
- Клиент сервиса на основе
System.ServiceModel.ClientBase. Использовать нельзя, но можно взять за основу интерфейс сервиса.
АтрибутовSystem.SerializableAttribute
иSystem.ComponentModel.DesignerCategoryAttribute
. Эти аттрибуты не поддерживаются, удаляем.
Свойствpublic System.Xml.XmlElement[] Any { get; set; }
. Меняем тип наSystem.Xml.Linq.XElement[]
.