28.08.2013

Если IE < 10 не хочет отправлять кроссдоменные запросы

Ситуация возникла после того, как проект был задеплоен на сервер. Прикол в том, что на IIS Express 8 и на IIS 7.5, установленные на локальной машине, все успешно работало. Запросы к API, размещенному на другом домене шли без проблем. Однако после выкладки на сервер IE 9 просто не слал ajax-запросы.

Проблему решил небольшой js, который посчастливилось найти на просторах интернета.
https://github.com/Malvolio/ie.xhr

Но стоит учесть, что он преобразует запрос в формат XDomainRequest, который в свою очередь имеет кучу ограничений. Например, нельзя присоединить к реквесту собственный хидер. Весь перечень ограничений легко можно найти в интернете — изучая материал, сто раз на него натыкался.


27.08.2013

JSONP Formatter для Web API

Для того, чтобы Web API отдавал данные в формате JSONP, необходимо:

1) установить package, прописав в Package Manager Console такую команду:
 Install-Package WebApiContrib.Formatting.Jsonp

2) в папку проекта App_Start добавить файл, содержащий следующий код:
public class FormatterConfig
    {
        public static void RegisterFormatters(MediaTypeFormatterCollection formatters)
        {
            var jsonFormatter = formatters.JsonFormatter;
            jsonFormatter.SerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
 
            // Insert the JSONP formatter in front of the standard JSON formatter.
            var jsonpFormatter = new JsonpMediaTypeFormatter(formatters.JsonFormatter);
            formatters.Insert(0, jsonpFormatter);
        }
    }

SerializerSettings  здесь исключительно для того, что задать правила именования свойств, поэтому по сути достаточно последних двух строк

3) зарегистрировать наш новый форматтер в Global.asax, добавив в метод Application.Start следующую строку: 

FormatterConfig.RegisterFormatters(GlobalConfiguration.Configuration.Formatters);


Предварительно необходимо, чтоб Web API был настроен на передачу JSON.
Для этого в WebApi.Register необходимо добавить две строки:


config.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
config.Formatters.Add(GlobalConfiguration.Configuration.Formatters.JsonFormatter);

20.08.2013

Кроссдоменный обмен данными между Web API и Web Application

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

И вот настало время внедрять мой Web API в основной проект, он же сайт. Сразу оговорюсь, что в API была заложена защита, как же без нее. Авторизацию реализовал при помощи встроенной Forms Authentication. Также была внедрена защита от поддельных запросов с других сайтов или Preventing Cross-Site Request Forgery (CSRF) Attacks. То есть каждый входящий запрос проверялся на наличие валидного RequestVerificationToken. Проблемы начались, когда пришло время авторизовываться.

В ходе долгих странствий по интернету, было выяснено:

для того, что отправить авторизационные куки с одного домена на другой, требуется в запросе (будь то ajax, get или post) указывать следующий параметр:

xhrFields: {
    withCredentials: true
},

Ок, API успешно записывает куки в Response и при обратном запросе к API они присоединяются. Но все это добро работало лишь в Chrome. Ни в Mozilla FF, ни в IE 9 кроссдоменный обмен данными не шел.

Еще полдня на бесконечных просторах мировой паутины и решение найдено:

для FF требовалось на стороне API добавить в WebApiConfig в метод Register вот эти строки:
var cors = new EnableCorsAttribute(домен сайта, "*", "*");
config.EnableCors(cors);

для IE требовалось в скрипте страницы дописать строку:
jQuery.support.cors = true;

Решение не ахти какое, но рабочее.
Добавлено спустя некоторое время: решение работает только на localhost (: