Leonardo Wildt
Leonardo Wildt

Reputation: 2599

CORS issue on Put

When i send a put to my Api i first get method OPTIONS and an error. It then hits my select action method again and it contains the put info.

  public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            var request = controllerContext.Request;
            if (request.IsInspectRequest())
            {
                var simulate = new ActionSelectSimulator();
                request.Properties[RequestHelper.ActionCache] = simulate.Simulate(controllerContext);
            }

            var selectedAction = _innerSelector.SelectAction(controllerContext);

            return selectedAction;
        }

I have a class that handles my preflight request.

   public class XHttpMethodOverrideHandler : DelegatingHandler
    {
        static readonly string[] httpOverrideMethods = { "PUT", "DELETE" };
        static readonly string[] accessControlAllowMethods = { "POST", "PUT", "DELETE" };
        static readonly string httpMethodOverrideHeader = "X-HTTP-Method-Override";
        static readonly string ORIGIN_HEADER = "ORIGIN";
        static readonly string accessControlAllowOriginHeader = "Access-Control-Allow-Origin";
        static readonly string accessControlAllowMethodsHeader = "Access-Control-Allow-Methods";
        static readonly string accessControlAllowHeadersHeader = "Access-Control-Allow-Headers";

        protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            try
            {
                if (request.Method == HttpMethod.Post && request.Headers.Contains(httpMethodOverrideHeader))
                {
                    var httpMethod = request.Headers.GetValues(httpMethodOverrideHeader).FirstOrDefault();
                    if (httpOverrideMethods.Contains(httpMethod, StringComparer.InvariantCultureIgnoreCase))
                        request.Method = new HttpMethod(httpMethod);
                }

                var httpResponseMessage = base.SendAsync(request, cancellationToken);

                if (request.Method == HttpMethod.Options && request.Headers.Contains(ORIGIN_HEADER))
                {
                    httpResponseMessage.Result.Headers.Add(accessControlAllowOriginHeader, request.Headers.GetValues(ORIGIN_HEADER).FirstOrDefault());
                    httpResponseMessage.Result.Headers.Add(accessControlAllowMethodsHeader, String.Join(", ", accessControlAllowMethods));
                    httpResponseMessage.Result.Headers.Add(accessControlAllowHeadersHeader, httpMethodOverrideHeader);
                    httpResponseMessage.Result.StatusCode = HttpStatusCode.OK;
                }
                else if (request.Headers.Contains(ORIGIN_HEADER))
                    httpResponseMessage.Result.Headers.Add(accessControlAllowOriginHeader, request.Headers.GetValues(ORIGIN_HEADER).FirstOrDefault());

                return httpResponseMessage;
            }
            catch (Exception ex)
            {
                ILoggerService logger = IocContainer.Container.TryGetInstance<ILoggerService>();
                if (logger != null)
                {
                    logger.Error(ex);
                }
                return Task.FromResult<HttpResponseMessage>(request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
            }

I also have added to my webconfig

 <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>

When i send my Put Ajax call i receive an error. It hits my method and performs my action but it sends an error. If i send the put request via postman then i have no problem. If i send it from the client I get an error because the first method it gets is {OPTIONS}. What am i missing? Here is my Ajax put

  $.ajax({
                    url: "http://localhost:61148/api/mycontroller",
                    contentType: "application/x-www-form-urlencoded; charset=UTF-8",
                    async: true,
                    type: "PUT",
                    data: sendData,
                    datatype: 'json',
                    crossDomain: true,
                    success: function () {

Upvotes: 1

Views: 177

Answers (1)

Leonardo Wildt
Leonardo Wildt

Reputation: 2599

I found the answer in a couple of other questions. The solution is so simple it hurts. If you're having this issue add an options method in your controller.

public HttpResponseMessage Options()
{
    var response = new HttpResponseMessage
    {
        StatusCode = HttpStatusCode.OK
    };
    return response;
}

Upvotes: 1

Related Questions