17

I am setting up a WebAPI endpoint for my API, but am having trouble getting my AngularJS calls to my PostRegister method to work.

The webAPI and Angular are on separate sites.

On the Startup.cs I have:

    public void Configuration(IAppBuilder app)
    {
        ConfigureOAuth(app);

        var config = new HttpConfiguration();

        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);

    }

    private void ConfigureOAuth(IAppBuilder app)
    {
        var oAuthServerOptions = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString(Paths.TokenPath),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
            Provider = Kernel.Get<IOAuthAuthorizationServerProvider>()
        };
        app.UseOAuthAuthorizationServer(oAuthServerOptions); 

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    }

Then on the controller, I have my method that is set to allow anonymous:

    [AllowAnonymous]
    public bool PostRegister(UserSignupForm form)
    {
        ...
    }

I've also updated the web.config:

 <system.webServer>
    <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>
  </system.webServer>

On the Angular side, I make a simple $http.post call:

    saveRegistration: function (registration) {
        return $http.post(baseUrl + '/api/signup/register', registration).then(function (response) {
            return response;
        });
    }

When making the call using Postman, I get a successful response, but when doing the same call from Angular, I get the 405 error.

405 Method Not Allowed

BitOfTech sample site, is sending the same request headers, but is able to get the Access-Control-Allow-XXX headers

enter image description here

I've updated my code to follow Token Based Authentication using ASP.NET Web API 2, Owin, and Identity

Andy T
  • 10,223
  • 5
  • 53
  • 95
  • can you post the relevant bits of routing code in your controller? – Claies Jan 18 '15 at 23:41
  • incidentally, your code really doesn't seem to resemble the article you linked at all, the signature of your `PostRegister()` function is nothing like any function in the code on the site, and doesn't seem to match the signature of the angular.js `$http.post` method either. – Claies Jan 19 '15 at 00:00
  • does other methods work? does it helps if you set [HttpPost] attribute above PostRegister()? (in case your routes are messed up...) – André Werlang Jan 19 '15 at 00:46
  • @AndrewCounts, I had already started on my project and couldn't get it to work, so I started adapting it to resemble the article I linked to. – Andy T Jan 19 '15 at 00:48
  • I doubt you are getting access-control headers in postman response. to get those attributes in postman response you would need to add origin attributes. also i dont see CORS enabled for webapi – harishr Jan 21 '15 at 15:57
  • Doesn't `app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);` enable CORS? – Andy T Jan 21 '15 at 16:00
  • no it doesnt enable it for web-api, it enables owin cors. [whats the difference - read here](http://stackoverflow.com/questions/27309380/owin-cors-or-web-api-cors), also have you checked your postman response. – harishr Jan 21 '15 at 16:50
  • btw i think there are 2 problem here, one is CORS and another is attribute allow-anonymous, the attribute problem would be easier to solve, given the CORS issue is resolved – harishr Jan 22 '15 at 04:10
  • I think you need to show more code, like the full Account controller ? and like Andrew said your angular code doesn't match your PostRegister method. This article uses Web API 2 together with AngularJS and you can download the code and have a look, you can register /login and retrieve data from the Web API. http://www.codeproject.com/Articles/742532/Using-Web-API-Individual-User-Account-plus-CORS-En – Omar.Alani Jan 23 '15 at 06:22
  • Maybe you need to enable CORS for your web api: Try adding `config.EnableCors(new EnableCorsAttribute("*", "*", "*"));` just right after `var config = new HttpConfiguration();` – Khanh TO Jan 23 '15 at 13:55
  • This is, like other already have mentioned, a CORS problem. To solve this issue you could add `OPTIONS` as allowed method. In your response the `Access-Control-Request-Headers` need to be set to `POST, OPTIONS`. – GuyT Jan 27 '15 at 14:36

5 Answers5

10

I had similar issue recently. I added controller handler for the pre-flight OPTIONS request and it solved the problem.

[AllowAnonymous]
[Route("Register")]
[AcceptVerbs("OPTIONS")]
public async Task<IHttpActionResult> Register()
{
    return Ok();
}
Sergey Kolodiy
  • 5,829
  • 1
  • 36
  • 58
  • CorsOptions.AllowAll should accept all verbs no? From XML comments "A policy that allows all headers, all methods, any origin and supports credentials" – Matt Morgan Jul 17 '17 at 15:58
3

You might need to allow cors in your application for response headers. Below is sample for what I do in node.

res.header('Access-Control-Allow-Origin', '*');

res.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS"); 

res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');

This could help you. Thanks.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
Sumit Arora
  • 91
  • 1
  • 5
2

The problem is not with the angular. Though you get a response in Postman, its not problem in angular that request is not giving you the response. Problem is by default Postman does not post the Origin attribute, which is needed to test CORS. Chrome does block the Origin attribute by default, hence the request is not treated as if its coming from a different domain.

So how to test CORS in Postman

you would need a different chrome extension with same name POSTMAN - Rest Client (Packaged App), and use its 'Request Interceptor toggle switch' to enable it to send the ORIGIN attribute.

read here, section restricted header

below is the sample screen shot when you dont send the ORIGIN attributes

WITHOUT ORIGIN

and the same request;s response in POSTMAN when you send the ORIGIN attribute

WITH ORIGIN

so if you see, when you add origin, that only when you get the ACCESS-CONTROL-* attributes in response.

I hope this also answer your query about

BitOfTech sample site, is sending the same request headers, but is able to get the Access-Control-Allow-XXX headers"

Web Api Part

Coming back to your case, you do not have CORS enabled in web-api. First enable CORS in web-api. To enable CORS globally use

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("www.example.com", "*", "*");
        config.EnableCors(cors);
        // ...
    }
}

-- you can find lot of resources around net on how to add it on controller level etc.

Angular Part

you first need to make sure that the CORS is working in POSTMAN and then try to access that url in angular.

to enable cors in angular you need below code in your app.config() function.

myApp.config(function($httpProvider) {
  $httpProvider.defaults.useXDomain = true;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

Note : For the Experts

Origin attributes is needed to test CORS. I am not very sure on this part, but seems like the case as per the response I see in Postman. It would be great if anyone can shed light on the role Origin attribute in Cors.

harishr
  • 17,807
  • 9
  • 78
  • 125
1

This sounds like a cross-origin issue. You should install Fiddler and check if the 405 response is caused by the pre-flight request (OPTIONS verb) that is issued by the browser when you're calling a resource on a different origin.

See this article for a nice explanation of CORS: http://www.html5rocks.com/en/tutorials/cors/

MvdD
  • 22,082
  • 8
  • 65
  • 93
  • Yes, it definitely is a CORS issue. I've added the request and response to my question. – Andy T Jan 19 '15 at 00:58
  • See if this question help you then: http://stackoverflow.com/questions/20079813/how-to-make-cors-authentication-in-webapi-2 – MvdD Jan 19 '15 at 01:16
1

I believe you are missing annotation on your API Controller, you should add annotation on APIController as

[RoutePrefix("api/signup")]

Otherwise your WebApiConfig should be have route define like Below

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

And to setup CORS you always need to send your credential on every single call to server. Then there is easy way to do this in angular by setting $http provider default option.

You can do this at config phase of angular.

CODE

  angular.module('myApp',[])
    .config([
        '$httpProvider',
        function($httpProvider) {
            $httpProvider.defaults.withCredentials = true;
        }
    ]);

Above setting will add credential in each $http call.

Also refer this post. Some what the same problem.

This may help to solve your problem. Thanks.

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299