Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
По умолчанию в целях безопасности браузер ограничивает ajax-запросы между различными доменами. Однако может возникнуть ситуация, когда в Web API нам потребуется выполнять подобные запросы. Для этого нам надо использовать при отправке запроса формат JSONP.
Чтобы задействовать JSONP в Web API, вначале добавим в проект NuGet-пакет WebApiContrib.Formatting.Jsonp:
Затем изменим в проекте Web API файл Global.asax:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using WebApiContrib.Formatting.Jsonp; // добавляем поддержку jsonp namespace CORSApp { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configuration.AddJsonpFormatter(); // добавляем поддержку jsonp AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } }
Допустим, приложение Web API запускается по адресу http://localhost:33384. Для теста создадим второе приложение ASP.NET MVC, которое запускается по другому адресу. Теперь чтобы обратиться из второго приложения к приложению web api через ajax, пропишем в представлении второго приложения следующий код:
<div id="result"> </div> <div><p><button class="btn" id="request">Запрос</button></p></div> @section scripts { <script> $(function () { $("#request").click(function() { $.ajax({ url: 'http://localhost:33384/api/values/', type: 'GET', dataType: 'jsonp', success: function (data) { $("#result").text(data); }, error: function (jqXHR, textStatus, errorThrown) { $('#result').text(jqXHR.responseText || textStatus); } }); }); }) </script> }
И после нажатия на кнопку будет выполняться запрос к стандартному методу Get контроллера ValuesController приложения Web API.
Несколько иное поведение реализует применение стандарта Cross Origin Resource Sharing (CORS), который также позволяет выполнять кроссдоменные запросы, но при этом имеет следующие преимущества: CORS более безопасный, поддерживает не только запросы Get, но и POST, PUT и т.д.
Но чтобы сделать CORS доступным в проекте Web API, надо добавить специальный NuGet-пакет Microsoft.AspNet.WebApi.Cors (пакет добавляется только в проект Web API, к которому идет запрос):
Затем откроем файл WebApiConfig.cs в папке App_Start и изменим в нем метод WebApiConfig.Register
:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Добавляем поддержку CORS config.EnableCors(); config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
Также в файле конфигурации web.config добавим в узел system.webServer новый элемент modules:
<system.webServer> <!-- остальное содержимое узла --> <modules runAllManagedModulesForAllRequests="true"></modules> </system.webServer>
Затем добавим атрибут [EnableCors] к контроллеру Web API:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.Cors; // пространство имен CORS namespace CORSApp.Controllers { [EnableCors(origins: "http://localhost:33419", headers: "*", methods: "*")] public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // остальные методы } }
Атрибут имеет три параметра:
origins: задает набор url, с которых разрешен доступ к данному ресурсу
headers: задает набор заголовков, которые допустимы для доступа к ресурсу
methods: определяет набор допустимых типов запроса
В использованной версии атрибута предполагается, что доступ к контроллеру values разрешен только с адреса http://localhost:33419 (в конце концевой слеш не используется!), причем разрешен для всех типов запроса - GET, POST, PUT, и любых заголовков.
Из приложения, которое запущено по адресу http://localhost:33419, мы можем обратиться к приложению web api с помощью стандартного запроса ajax:
<div id="result"> </div> <div><p><button class="btn" id="request" value="Запрос">Запрос</button></p></div> @section scripts { <script> $(function () { $("#request").click(function() { $.ajax({ url: 'http://localhost:33384/api/values/', type: 'GET', //dataType: 'json', success: function (data) { $("#result").text(data); }, error: function (jqXHR, textStatus, errorThrown) { $('#result').text(jqXHR.responseText || textStatus); } }); }); }) </script> }
Если мы хотим, чтобы ресурс был доступен для всех url, то для параметра origins можно поставить звездочку:
[EnableCors(origins: "*", headers: "*", methods: "*")]
Также мы можем задать набор ресурсов, методов, заголовков через запятую:
[EnableCors(origins: "http://localhost:34822,http://www.example.com", headers: "accept,content-type,origin", methods: "get,post")]
Как и другие атрибуты, этот атрибут может быть задан на уровне, контроллера, на уровне одного метода или глобально для всего приложения. Чтобы задать атрибут глобально, изменим класс WebApiConfig в папке App_Start:
using System.Web.Http.Cors; //........ public static class WebApiConfig { public static void Register(HttpConfiguration config) { var cors = new EnableCorsAttribute("http://www.example.com", "*", "*"); config.EnableCors(cors); config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
Если мы применяем атрибут глобально или к контроллеру, но при этом хотим исключить из его действия какой-нибудь метод, то для метода можно использовать атрибут [DisableCors]:
[EnableCors(origins: "http://localhost:33419", headers: "*", methods: "*")] public class ValuesController : ApiController { [DisableCors] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } }