CORS support for ASP.NET Web API (转载)
CORS support for ASP.NET Web API
Overview
Cross-origin resource sharing (CORS) is a standard that allows web pages to make AJAX requests to another domain. It relaxes the same-origin policy implemented on the web browsers that limits the calls to be within the same domain.
The CORS spec (http://www.w3.org/TR/cors/) defines the way the server and browser interact in order to make cross origin calls (that is, cross domain). Most of the modern browsers today already support CORS. Our goal is to enable the support for our Web API services.
Required Assemblies
System.Web.Cors.dll
This assembly contains the core CORS library and has no dependency on System.Web.dll or System.Web.Http.dll.
System.Web.Http.Cors.dll
This assembly contains the library for enabling CORS on Web API and has dependency on System.Web.Cors.dll and System.Web.Http.dll.
Scenarios
Enabling CORS
We’ve added a new extension method to the HttpConfiguration to enable CORS. With this, you can enable the support globally, per controller or per action.
Globally
You can define a global setting when calling EnableCors. For example, the following will enable CORS globally, allowing all origins, methods, and headers. There are many settings on the EnableCorsAttribute that you can configure and are shown later in this document.
using System.Web.Http.Cors;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// other settings removed for clarity config.EnableCors(new EnableCorsAttribute());
}
}
Per Controller
The support can also be scoped to the controller. First you just need to call EnableCors without providing a global setting (that is, (new EnableCorsAttribute()).
using System.Web.Http.Cors;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// other settings removed for clarity config.EnableCors();
}
}
Then you can declare the EnableCorsAttribute on the controller to enable CORS.
[EnableCors]
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
} public string Get(int id)
{
return "value " + id;
}
}
Per Action
In a similar fashion, you can enable CORS on a single action by first calling EnableCors.
using System.Web.Http.Cors;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// other settings removed for clarity config.EnableCors();
}
}
And then declare the EnableCorsAttribute on an action.
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
} [EnableCors]
public string Get(int id)
{
return "value " + id;
}
}
Attribute precedence
When you have the EnableCorsAttribute applied on all scopes (globally, per-controller, per-action), the closest one to the resource wins. Therefore the precedence is defined as follows:
- Action
- Controller
- Global
Excluding a controller or an action from EnableCors
You can use [DisableCors] attribute to exclude a controller or and action from the global or per-controller settings. For example, the following will enable CORS for all the actions in the ValuesController except for Get(int id).
[EnableCors]
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
} [DisableCors]
public string Get(int id)
{
return "value " + id;
}
}
Configuring [EnableCors] attribute
There’re few settings under the EnableCorsAttribute. These settings are defined by the CORS spec (http://www.w3.org/TR/cors/#resource-processing-model).
- Origins
- Headers
- Methods
- ExposedHeaders
- SupportsCredentials
- PreflightMaxAge
By default, EnableCorsAttribute will allow all origins, methods and headers. Note that when you declare the attribute on an action it automatically assumes the HTTP Method of the action that you declared on.
As soon as you specify the origins, you are basically limiting the access to the specified origins. The same applies to the methods and the headers.
For example, the following will only allow “http://localhost” and “http://sample.com” to access the ValuesController from the browser though AJAX. Note that it is still allowing any methods and headers because they’re not specified.
[EnableCors(Origins = new[] { "http://localhost", "http://sample.com" })]
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public string Get(int id)
{
return "value " + id;
}
}
Implementing a custom ICorsPolicyProvider
You can implement ICorsPolicyProvider to load the CORS settings/policy dynamically from other sources such as the web.config file or a database. In fact, both the EnableCorsAttribute and DisableCorsAttribute implement this interface internally.(这里就是让Cors可以从数据库或配置文件读取访问策略的关键所在)
namespace System.Web.Http.Cors
{
public interface ICorsPolicyProvider
{
Task GetCorsPolicyAsync(HttpRequestMessage request);
}
}
Note that the ICorsPolicyProvider is async so that we don’t block the thread on I/O.
Sample
Here is a custom implementation of ICorsPolicyProvider that loads the origins from web.config.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class EnableCorsAppSettingsAttribute : Attribute, ICorsPolicyProvider
{
private CorsPolicy _policy; public EnableCorsAppSettingsAttribute(string appSettingOriginKey)
{
_policy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true
}; // loads the origins from AppSettings
string originsString = ConfigurationManager.AppSettings[appSettingOriginKey];
if (!String.IsNullOrEmpty(originsString))
{
foreach (var origin in originsString.Split(','))
{
_policy.Origins.Add(origin);
}
}
} public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
{
return Task.FromResult(_policy);
}
}
You can apply it on the controller/action just like EnableCorsAttribute.
[EnableCorsAppSettings("internal:origins")]
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public string Get(int id)
{
return "value " + id;
}
}
And it will read the “internal:origins” appSetting from the web.config.
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="internal:origins" value="http://example.com,http://webapisample.azurewebsites.net" />
</appSettings>
Implementing a custom ICorsPolicyProviderFactory
ICorsPolicyProviderFactory is an abstraction that allows you to specify how the ICorsPolicyProvider is retrieved. By default we provide the AttributeBasedPolicyProviderFactory which allows you to specify the ICorsPolicyProvider as attributes ([EnableCors], [DisableCors]). However you can extend the ICorsPolicyProviderFactory to create a centralized configuration model.
namespace System.Web.Http.Cors
{
public interface ICorsPolicyProviderFactory
{
ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request);
}
}
You can register the custom ICorsPolicyProviderFactory through SetCorsPolicyProviderFactory extension method.
public static class HttpConfigurationExtensions
{
// other extensions removed for clarity
public static void SetCorsPolicyProviderFactory(this HttpConfiguration httpConfiguration, ICorsPolicyProviderFactory corsPolicyProviderFactory);
}
Sample
Here is a custom implementation of ICorsPolicyProviderFactory that allows you to configure the CORS settings through your own CorsConfiguration class instead of attributes.
public class ConfigBasedPolicyProviderFactory : ICorsPolicyProviderFactory
{
private CorsConfiguration _configuration; public ConfigBasedPolicyProviderFactory(CorsConfiguration configuration)
{
_configuration = configuration;
} public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
{
var routeData = request.GetRouteData();
if (routeData == null || !routeData.Values.Keys.Contains("controller"))
{
return null;
}
var controller = routeData.Values["controller"] as string;
return _configuration.GetPolicyForRequest(controller);
}
}
public class CorsConfiguration
{
private Dictionary<string, EnableCorsAttribute> _settings =
new Dictionary<string, EnableCorsAttribute>(); public void AddSetting(string controller, EnableCorsAttribute policyProvider)
{
_settings.Add(controller, policyProvider);
} public virtual EnableCorsAttribute GetPolicyForRequest(string controller)
{
EnableCorsAttribute policyProvider;
_settings.TryGetValue(controller, out policyProvider);
return policyProvider;
}
}
Once the ConfigBasedPolicyProviderFactory is registered, it will enable CORS on ValuesController and UsersController.
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.AddSetting("Values", new EnableCorsAttribute());
corsConfig.AddSetting("Users", new EnableCorsAttribute { Origins = new[] { "http://localhost" } });
config.SetCorsPolicyProviderFactory(new ConfigBasedPolicyProviderFactory(corsConfig)); config.EnableCors();
Integration with Web API Tracing
When you call config.EnableCors(), it automatically adds the necessary tracers when the ITraceWriter is provided.
using System.Web.Http.Cors;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// other settings removed for clarity config.EnableSystemDiagnosticsTracing(); config.EnableCors();
}
}
It will emit traces similar to what’s highlighted below when you have the Web API tracing package installed and enabled.
iisexpress.exe Information: 0 : Request, Method=GET, Url=http://localhost:33150/api/Values, Message='http://localhost:33150/api/Values'
iisexpress.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Will use same 'XmlMediaTypeFormatter' formatter', Operation=XmlMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Will use same 'FormUrlEncodedMediaTypeFormatter' formatter', Operation=FormUrlEncodedMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Will use same 'JQueryMvcFormUrlEncodedFormatter' formatter', Operation=JQueryMvcFormUrlEncodedFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Values', Operation=DefaultHttpControllerSelector.SelectController
iisexpress.exe Information: 0 : Message='CorsSample.Controllers.ValuesController', Operation=DefaultHttpControllerActivator.Create
iisexpress.exe Information: 0 : Message='CorsSample.Controllers.ValuesController', Operation=HttpControllerDescriptor.CreateController
iisexpress.exe Information: 0 : Message='Selected action 'Get()'', Operation=ApiControllerActionSelector.SelectAction
iisexpress.exe Information: 0 : Operation=HttpActionBinding.ExecuteBindingAsync
iisexpress.exe Information: 0 : Operation=QueryableAttribute.ActionExecuting
iisexpress.exe Information: 0 : Message='Action returned 'System.String[]'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
iisexpress.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
iisexpress.exe Information: 0 : Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=QueryableAttribute.ActionExecuted, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=ValuesController.ExecuteAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Response, Status=200 (OK), Method=GET, Url=http://localhost:33150/api/Values, Message='Content-type='application/json; charset=utf-8', content-length=unknown'
iisexpress.exe Information: 0 : Operation=CorsMessageHandler.SendAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Message='CorsPolicyProvider selected: 'System.Web.Http.Cors.EnableCorsAttribute'', Operation=ConfigBasedPolicyProviderFactory.GetCorsPolicyProvider
iisexpress.exe Information: 0 : Message='CorsPolicy selected: 'AllowAnyHeader: True, AllowAnyMethod: True, AllowAnyOrigin: True, PreflightMaxAge: null, SupportsCredentials: False, Origins: {}, Methods: {}, Headers: {}, ExposedHeaders: {}'', Operation=EnableCorsAttribute.GetCorsPolicyAsync
iisexpress.exe Information: 0 : Message='CorsResult returned: 'IsValid: True, AllowCredentials: False, PreflightMaxAge: null, AllowOrigin: *, AllowExposedHeaders: {}, AllowHeaders: {}, AllowMethods: {}, ErrorMessages: {}'', Operation=CorsEngine.EvaluatePolicy
iisexpress.exe Information: 0 : Operation=JsonMediaTypeFormatter.WriteToStreamAsync
iisexpress.exe Information: 0 : Operation=ValuesController.Dispose
CORS support for ASP.NET Web API (转载)的更多相关文章
- 跨域资源共享(CORS)在ASP.NET Web API中是如何实现的?
在<通过扩展让ASP.NET Web API支持W3C的CORS规范>中,我们通过自定义的HttpMessageHandler自行为ASP.NET Web API实现了针对CORS的支持, ...
- Enabling Cross-Origin Requests in ASP.NET Web API 2
Introduction This tutorial demonstrates CORS support in ASP.NET Web API. We’ll start by creating two ...
- JavaScript跨域调用、JSONP、CORS与ASP.NET Web API[共8篇]
[第1篇] 同源策略与JSONP 浏览器是访问Internet的工具,也是客户端应用的宿主,它为客户端应用提供一个寄宿和运行的环境.而这里所说的应用,基本是指在浏览器中执行的客户端JavaScript ...
- [转] JSON Web Token in ASP.NET Web API 2 using Owin
本文转自:http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/ ...
- JSON Web Token in ASP.NET Web API 2 using Owin
In the previous post Decouple OWIN Authorization Server from Resource Server we saw how we can separ ...
- ASP.NET Web API之消息[拦截]处理
标题相当难取,内容也许和您想的不一样,而且网上已经有很多这方面的资料了,我不过是在实践过程中作下记录.废话少说,直接开始. Exception 当服务端抛出未处理异常时,most exceptions ...
- ASP.NET Web API系列教程目录
ASP.NET Web API系列教程目录 Introduction:What's This New Web API?引子:新的Web API是什么? Chapter 1: Getting Start ...
- ASP.NET Web API系列教程(目录)(转)
注:微软随ASP.NET MVC 4一起还发布了一个框架,叫做ASP.NET Web API.这是一个用来在.NET平台上建立HTTP服务的Web API框架,是微软的又一项令人振奋的技术.目前,国内 ...
- Self-Host c#学习笔记之Application.DoEvents应用 不用IIS也能執行ASP.NET Web API
Self-Host 寄宿Web API 不一定需要IIS 的支持,我们可以采用Self Host 的方式使用任意类型的应用程序(控制台.Windows Forms 应用.WPF 应用甚至是Wind ...
随机推荐
- 原生javascript实现类似jquery on方法的行为监听
原生javascript有addEventListener和attachEvent方法来注册事件,但有时候我们需要判断某一行为甚至某一函数是否被执行了,并且能够获取前一行为的参数,这个时候就需要其他方 ...
- ionCube 安装
有些程序在php环境下运行需要安装ionCube Loader的扩展支持,得到如下提示 Site error: the ionCube PHP Loader needs to be installed ...
- DOM操作表单(select下拉选框)
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- Java基础之引用(String,char[],Integer)总结于牛客网的专项练习题
1.String的引用: 下列代码执行后的结果为: public class Test { public static void main(String[] args) { StringBuffer ...
- Java学习笔记(5)----使用正则表达式解决Google Code Jam Qualification2009赛题 Alien Language
原题地址:https://code.google.com/codejam/contest/90101/dashboard#s=p0 题目描述: Problem After years of study ...
- Java快速入门-04-Java.util包简单总结
学Java的程序员,lang包和util包最好是要过一遍的. 建议大家都序下载一个离线版开发文档,查阅非常方便,我给大家提供一个中文版 jdk1.8 离线文档,查看:JAVA - JDK 1.8 AP ...
- Dancing Line、网易蜗牛读书——创新性分析
Dancing Line——视听效果极佳的解压游戏 介绍:跳舞的线是由猎豹移动公司和BoomBitInc制作的一款游戏,发行于2016年12月12日. 游戏规则:跟着音乐的节奏点击屏幕,完成转向,躲避 ...
- 转:Java Socket编程
对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是Socket.服务端和客户端之间通过Socket建立连接,之后它们就可以进行通信了.首先ServerSocket将 ...
- 并发编程------->操作系统的发展
手工操作 —— 穿孔卡片 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念. 程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然 ...
- VS :不会命中断点 代码版本与原始版本不同
设置了断点,但是无法中断,提示"不会命中断点 代码版本与原始版本不同".这种情况下一般是生成的bin\debug下面的文件与实际代码不符. 但是这次确实没有问题,重新更新程序,清理 ...