Около года назад мы начали работу над Evernote для Windows Phone 7. Тогда нашей первоочередной задачей было заставить наш SDK, использующий C#, работать с Silverlight, чтобы получить возможность доступа к Evernote API. Наш API построен на Apache Thrift, а генератор кода Thrift для C# используют синхронный HTTP-стек на .NET. Silverlight, между тем, поддерживает только асинхронную сетевую модель. Поэтому Дамиану Мэйерсу, нашему главному разработчику клиента для Windows Phone 7, пришлось какое-то время подумать над тем, как же заставить все это работать. В результате он внес изменения (подробно описав их у себя в блоге), которые позволили генератору кода C# и Thrift поддерживать обе сетевые модели. Этот код вы можете найти в нашем SDK для C#.
И вот год спустя мы вновь работаем над JavaScript-приложениями для Windows 8 Metro, которым необходимо обеспечить доступ к Evernote API из managed-кода C#. Вновь сталкиваемся с несовместимостью Thrift с, на сей раз, API .NET для Metro-приложений. Сегодня мы решили поделиться с вами способом решения этой проблемы.
Для того, чтобы исправить ошибки компиляции, мы начали с создания библиотеки классов Metro в Visual Studio для классов оболочек Evernote API и Thrift. Во-первых, наш код использовал асинхронные сетевые модели, если в процессе компиляции обнаруживался SILVERLIGHT. Для Metro мы добавили NETFX_CORE:
Далее выяснилось, что классы I/O в .NET API для Metro-приложений больше не определяют методы Close(). В Microsoft подробно объяснили нам, как поступать в этом случае:
Также в Microsoft нам посоветовали заменить наши двухэтапные сетевые операции (Begin* и End*) новыми ReadAsync и оператором ожидания, но мы решили пока ничего не усложнять и не менять, поскольку старые модели, похоже, еще работают.
При формировании запросов к API все клиенты Evernote посылают HTTP-заголовки с заданным User-Agent — это позволяет нам легко идентифицировать приложения, делающие запросы, в серверных логах. Свойство HttpWebRequest.UserAgent, которое мы использовали для установки User-Agent для Silverlight, было удалено в .NET API для Metro-приложений. Новый HttpClient API позволяет нам устанавливать определенный User-Agent, но использование HttpClient требует от нас перехода к новой модели ожидания ответа, а, как уже говорилось выше, мы пока не готовы к столь значительным изменениям. На текущий момент мы оставили User-Agent в покое и миримся с утраченной возможностью определять, кто делает запросы к API. В связи с тем, что модель ожидания, по-видимому, будет использоваться в будущем, мы скорее всего разработаем третью модель сетевого взаимодействия, которая будет ее поддерживать, и вернем поддержку User-Agent.
Благодаря этим трем изменениям мы смогли скомпилировать библиотеку классов. Однако библиотеки классов могут быть использованы только Metro-приложениями, разработанными на managed-языке. Наш API используется JavaScript-приложением, а значит нам нужно упаковать библиотеки в файл WinMD. Но попробуйте переключить формат генерации кода вашего проекта с Class Library на WinMD, и вы обнаружите, что файлы WinMD привносят некоторые серьезные ограничения:
К счастью, ограничения файлов WinMD касаются только интерфейса, который они представляют в используемом коде. Вместо того, чтобы пытаться использовать в приложении наш полный клиентский API, мы просто добавили обертку — проект, который компилируется как WinMD, поддерживает логику отдельных операций с API и предоставляет приложению более простой API.
С моделью библиотеки-обертки для приложения мы получили (с минимальными изменениями в существующем коде) работающее Metro-приложение, способное полноценно работать с API Evernote. Мы рады, что пользователи принимают Windows 8 и Metro, и надеемся, что в будущем “Metro-приложения” станут настолько повсеместны, что этот термин будет вытеснен обычнм термином “приложения”.
Решение для Visual Studio 11 с нашим модифицированным SDK и пробным приложением доступно на GitHub. Попробуйте его и обязательно расскажите нам о том, что у вас получилось.
Автор: Roberto