29

I have created a web api 2 and I'm trying to do a cross domain request to it but I'm getting the following error:

OPTIONS http://www.example.com/api/save 405 (Method Not Allowed)

I have had a look around and most resolutions for this problem are saying that I need to install CORs from NuGet and enable it so I have installed the package and marked my controller with

[EnableCors("*", "*", "*")]

But this still hasn't resolved the problem.

My ApiController only has the following Save method in:

[ResponseType(typeof(int))]
public IHttpActionResult Save(Student student)
{
    if (ModelState.IsValid)
    {
        using (StudentHelper helper = new StudentHelper())
        {
            return Ok(helper.SaveStudent(student));
        }
    }
    else
    {
        return BadRequest(ModelState);
    }
}

This is my js from a different domain:

$.ajax({
    type: "POST",
    crossDomain: true,
    data: JSON.stringify(student),
    crossDomain: true,
    url: 'http://www.example.com/api/save',
    contentType: "application/json",
    success: function (result) {
        console.log(result);
    }
});

Is there something else I need to do to enable this?

6 Answers6

26

Via nuget make the installation of the CORS web API package for your project:

Install-Package Microsoft.AspNet.WebApi.Cors

In WebApiConfig add the following lines:

var cors = new EnableCorsAttribute ("*", "*", "*");
config.EnableCors (cors);
  • 2
    I had to remove the star for the origin parameter and set an url : `new EnableCorsAttribute ("https://myservicesite", "*", "*");` With the star parameter the OPTIONS request always send an 405 error... – NicoD Jul 22 '16 at 16:53
  • 1
    The OP stated that they had already tried this and it didn't work. – Scott Weldon May 09 '17 at 23:49
  • 1
    I've read the MS docs with WebApiConfig but what if I don't have this file in an existing application? – Alexander Pravdin Feb 05 '19 at 16:49
7

Ensure that you have OPTIONS as one of the allowed verb in your web.config and that it's being handled by the default handler.

<system.web>
...
  <httpHandlers>
  ... 
    <add path="*" verb="OPTIONS" type="System.Web.DefaultHttpHandler" validate="true"/>
    <add path="*" verb="TRACE" type="System.Web.DefaultHttpHandler" validate="true"/>
    <add path="*" verb="HEAD" type="System.Web.DefaultHttpHandler" validate="true"/>
Code Uniquely
  • 6,356
  • 4
  • 30
  • 40
  • This was definitely what was preventing me from achieving CORS to work correctly! Microsoft documentation is usually confusing. I followed [this tutorial](https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api) but they did not mention about the `system.web`.`httpHandlers` section. In my case I have a MVC with WebApi running together. – Reuel Ribeiro May 15 '19 at 06:26
5

This one solved my problem

Step 1

Install the Cors package Microsoft.AspNet.WebApi.Cors (Right Click Solution > Manage Nuget Package > And Then Search for Cors)

Step 2

put this line in the WebApiConfig.cs file

public static void Register(HttpConfiguration config)
{
    config.EnableCors(new EnableCorsAttribute("http://localhost:3000", headers: "*", methods: "*"));        
    .
    .
    .        
} 

Change http://localhost:3000 to the address of the API Caller

user2546477
  • 113
  • 1
  • 2
  • 5
2

In the end I have solved this by changing the ajax request. I found out that the OPTIONS preflight is only sent in certain situations - one of them being if the request contains a Content-Type that is not one of the following types:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

So by removing the content-type in my ajax request and changing it to the following:

$.ajax({
    type: "POST",
    crossDomain: true,
    data: student,
    dataType: 'json',
    url: 'http://www.example.com/api/save',
    success: function (result) {
        console.log(result);
    }
});

I was able to get it working.

This page has useful information about simple requests and how to avoid preflight requests

  • 9
    This doesn't solve the problem, it avoids it. For those who need to actually support preflight OPTIONS requests, this is not useful. – defines May 24 '16 at 23:44
  • 2
    @defines this solves my problem so there is no need to downvote - my problem was that I needed a simple request as I didn't need to support preflight. If someone is looking for how to support preflight, this question isn't about that, it is about how I could get my ajax call to talk to my web api - and the answer was to make a simple request, not to enable support for preflight –  May 25 '16 at 13:44
  • 4
    The title of the question is about OPTIONS returning 405. You avoid the OPTIONS request altogether. This isn't an answer to that at all, it simply avoids it. – defines May 26 '16 at 12:13
  • 3
    @defines The quesiton is how to solve the problem of getting that error, by avoiding the call that solves the problem. Problem solved = question answered, just becuase you don't agree with the method of solving the problem doesn't meant that you have to downvote a correct answer. Downvoting is meant to be for inaccurate, wrong or badly written answers. If you have a better way of accepting the options, then by all means, enlighten us all, after all that's what this place is for, to get different answers to solving the same problem –  May 27 '16 at 12:14
  • 3
    I respectfully disagree. Most people searching for a similar problem by the title of the question actually need to solve it, not work around it. If I expose a public API, I need to support standard operations, not instruct consumers to support a workaround. Incidentally, I was able to solve this and have offered a solution (one of many possible working solutions) to the actual problem - you can read my answer to a similar question here: http://stackoverflow.com/a/37425746/120990 – defines May 27 '16 at 20:40
  • I would remove my downvote if I could, as this does solve the problem in situations where it's acceptable to change the content-type header. But I do humbly disagree with this approach as an accepted answer to the question as it's stated. Unfortunately, SO won't let me change my vote unless you edit the answer (hint). – defines May 27 '16 at 20:47
  • thank you for the information, it work when i deleted Content-Type – Idriss Benbassou Jun 21 '18 at 12:37
  • Great! It solved my problem. Set data as object, instead of string json, and remove the content-type in the ajax call. Thanks! – Jose Ramon Garcia Oct 30 '21 at 19:47
0

Also try using the withcredentials ajax request option

    $.ajax({
     type: "POST",
     crossDomain: true,
     data: JSON.stringify(student),
     withCredentials: true,
     url: 'http://www.example.com/api/save',
     contentType: "application/json",
     success: function (result) {
      console.log(result);
     }
   });
Bilal
  • 182
  • 13
  • Ok! does your webapi config file looks like this? public static class WebApiConfig { public static void Register(HttpConfiguration config) { // New code config.EnableCors(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } – Bilal Oct 30 '14 at 12:59
  • Hi, yes I have the enable cors in the app_start –  Oct 31 '14 at 09:03
0

I was calling .net Web API from angular app and was getting 405 method not allowed error. I figured out that I was missing headers options in angular http.post. So I added header 'Content-Type': 'application/json' in the http request in angular, which solved my error and successfully hit the wpi action.

So to resolve the error, use EnableCors in the .net web api in WebAPIConfig require reference (System.Web.Http.Cors). Like this:

EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);

And add the header in angular http. Hope it helps someone.

Werner Hertzog
  • 2,002
  • 3
  • 24
  • 36