Last active
January 10, 2020 11:45
-
-
Save dereklawless/5849425 to your computer and use it in GitHub Desktop.
CORS support for ASP.NET Web API.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// An attribute to allow a CORS preflight request to a decorated action, returning an HTTP 200 OK status code. | |
/// </summary> | |
/// <remarks>See <see href="http://www.html5rocks.com/en/tutorials/cors/"/> for more details.</remarks> | |
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] | |
public class AllowCorsPreflightAttribute : ActionFilterAttribute | |
{ | |
public override void OnActionExecuting(HttpActionContext actionContext) | |
{ | |
var headers = actionContext.Request.Headers; | |
// Determine whether this is a CORS request. | |
if (headers.Contains(CorsHeaders.Origin)) | |
{ | |
if (actionContext.Request.Method == HttpMethod.Options) | |
{ | |
if (headers.Contains(CorsHeaders.AccessControlRequestMethod)) | |
{ | |
// Determine whether the requested HTTP method is supported by the action. | |
var requestedHttpMethod = headers.GetValues(CorsHeaders.AccessControlRequestMethod).FirstOrDefault(); | |
if (actionContext.ActionDescriptor.SupportedHttpMethods.Any(m => m.Method == requestedHttpMethod)) | |
{ | |
// Allow the request, additional CORS headers may be defined elsewhere. | |
actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK); | |
} | |
} | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// A custom controller configuration attribute, for wiring up CORS-aware action selectors. | |
/// </summary> | |
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] | |
public class CorsControllerConfigurationAttribute : Attribute, IControllerConfiguration | |
{ | |
/// <summary> | |
/// Gets or sets the action selector type. | |
/// </summary> | |
/// <value>The action selector type.</value> | |
public Type ActionSelector { get; set; } | |
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) | |
{ | |
if (controllerSettings == null) | |
{ | |
throw new ArgumentNullException("controllerSettings"); | |
} | |
if (controllerDescriptor == null) | |
{ | |
throw new ArgumentNullException("controllerDescriptor"); | |
} | |
controllerSettings.Services.Replace(typeof(IHttpActionSelector), Activator.CreateInstance(ActionSelector)); | |
} | |
} | |
/// <summary> | |
/// A custom controller action selector, for CORS preflight (HTTP OPTIONS) requests. | |
/// </summary> | |
/// <remarks>See <see href="http://www.html5rocks.com/en/tutorials/cors/"/> for more details.</remarks> | |
public class CorsPreflightActionSelector : ApiControllerActionSelector | |
{ | |
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) | |
{ | |
if (controllerContext == null) | |
{ | |
throw new ArgumentNullException("controllerContext"); | |
} | |
var originalRequest = controllerContext.Request; | |
var isCorsRequest = originalRequest.Headers.Contains(CorsHeaders.Origin); | |
if (originalRequest.Method == HttpMethod.Options && isCorsRequest) | |
{ | |
// Get the 'Access-Control-Request-Method' HTTP method value sent in the request. | |
var accessControlRequestMethod = originalRequest.Headers.GetValues(CorsHeaders.AccessControlRequestMethod) | |
.FirstOrDefault(); | |
if (!string.IsNullOrEmpty(accessControlRequestMethod)) | |
{ | |
// Create a new request for the HTTP method and URI specified in the preflight request. | |
var modifiedRequest = new HttpRequestMessage(new HttpMethod(accessControlRequestMethod), originalRequest.RequestUri); | |
controllerContext.Request = modifiedRequest; | |
// Select the action specified in the new request. | |
var actualDescriptor = base.SelectAction(controllerContext); | |
controllerContext.Request = originalRequest; | |
if (actualDescriptor != null) | |
{ | |
// The action requested exists, determine whether this CORS request is allowed. | |
if (actualDescriptor.GetFilters().OfType<AllowCorsPreflightAttribute>().Any()) | |
{ | |
return actualDescriptor; | |
} | |
} | |
} | |
} | |
return base.SelectAction(controllerContext); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment