2

I have read everything I can find on the subject of ASP.NET Core and CORS and I believe I understand most of it but, I'll be damned if I can get it to work. I'm using the Chrome browser, here is the data:

Prefilght:

General:
Request URL:http://localhost:34376/api/login
Request Method:OPTIONS
Status Code:204 No Content
Remote Address:[::1]:34376

Response Headers:
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:access-control-allow-origin,content-type
Access-Control-Allow-Origin:http://localhost:3000
Date:Wed, 23 Nov 2016 03:05:00 GMT
Server:Kestrel
Vary:Origin
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcUHJvamVjdHNcbXZjXFNob3BVc1NlcnZpY2Vcc3JjXFNob3BVc1NlcnZpY2VcYXBpXGxvZ2lu?=

Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:access-control-allow-origin, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:localhost:34376
Origin:http://localhost:3000
Referer:http://localhost:3000/authentication
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36

Post:

Request URL:http://localhost:34376/api/login
Request Method:POST
Status Code:500 Internal Server Error
Remote Address:[::1]:34376

Response Headers:
view source
Content-Length:0
Date:Tue, 22 Nov 2016 03:11:40 GMT
Server:Kestrel
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcUHJvamVjdHNcbXZjXFNob3BVc1NlcnZpY2Vcc3JjXFNob3BVc1NlcnZpY2VcYXBpXGxvZ2lu?=

Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Access-Control-Allow-Origin:true
Connection:keep-alive
Content-Length:87
Content-Type:application/json
Host:localhost:34376
Origin:http://localhost:3000
Referer:http://localhost:3000/authentication
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36

Request Payload:
view source
{userName: "", email: "irv@testing.com", password: "!P@ssw0rd", rememberMe: false}
   email: "irv@testing.com"
   password: "!P@ssw0rd"
   rememberMe: false
   userName:""

ASP.NET Core code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options => {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials().Build() );
    });
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseCors("CorsPolicy");

    app.UseApplicationInsightsRequestTelemetry();

    app.UseApplicationInsightsExceptionTelemetry();

    app.UseMvc();
}

ASP.NET Core Controller:

[EnableCors("CorsPolicy")]
[Produces("application/json")]
[Route("api/Authentication")]
public class AuthenticationController : Controller
{
    private IUnitOfWork _unitOfWork;
    public AuthenticationController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    [HttpPost]
    [Route("/api/login")]
    public JsonResult Login([FromBody]LoginInfo loginInfo)
    {
        return Json(new { id_token = _unitOfWork.Users.CreateJwt(loginInfo) });
    }

Here is the Angular code:

@Injectable()
export class AuthenticationService {
private _currentAdminMode: boolean = false;

constructor(private _http: Http, private _config: ConfigurationService) {
}

public login(logInfo: LoginInfo): Observable<TokenContainer> {
    var headers = new Headers();
    headers.append('Content-Type', 'application/json');

    //return an observable
    return this._http.post(this._config.hostPrefix + '/api/login', JSON.stringify(logInfo), { headers: headers })
        .map((response) => {
            return <TokenContainer>(response.json());
        });
}

The exact error that I'm getting in the console of the browser is:

XMLHttpRequest cannot load http://localhost:34376/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500.

Notice that I'm getting a 500 error from the POST request. That doesn't seem like the error the server would send if there was a CORS issue. I think it's something else but, all of this code worked in single domain, now that it's CORS something is going haywire. anyway I have read everything I can find and nothing is working. I'm thinking that it might have something to do with the WebAPI route.

Thanks for any help you can give!

Irv Lennert
  • 555
  • 5
  • 20
  • What is the exact error you're getting out of making requests to your API? Are you sure they are CORS-related? – Harry Ninh Nov 24 '16 at 01:38
  • I edited the questions with the exact error from the console of the browser. Not sure where the problem is and I have no idea how to debug it farther. I have placed a break point on the controller action method and I can tell you I never get to that break point. Thanks! – Irv Lennert Nov 24 '16 at 02:14
  • Are you able to login using Postman or similar app? – Harry Ninh Nov 24 '16 at 02:17
  • I get the same result with Postman, I just tried.... Hmm – Irv Lennert Nov 24 '16 at 02:30
  • But this exact server code worked in single domain (no CORS) though it was also serving a web page and now it's not – Irv Lennert Nov 24 '16 at 02:31
  • Just a hunch but how about adding withCredentials in your request options? `{ headers: headers, withCredentials: true }` – Adrian Nov 24 '16 at 02:33
  • I think it's not at all a CORS problem I'm looking at my code which I lifted from another project, and I think I didn't bring over IOC rules. and the Entity context stuff, no wonder it's blowing up!. Thanks for opening my eyes! Adrian and Harry, Thanks... – Irv Lennert Nov 24 '16 at 03:15
  • Thanks all, I really forgot to finish moving the code.... Real stupid... Was doing everything right with CORS. It's all working now. Now I'll just tighten everything up. – Irv Lennert Nov 24 '16 at 03:29
  • @IrvLennert Hi, could you give some details, because I have the same error? – user348173 Dec 18 '16 at 16:41

1 Answers1

7

Well, I've spent a day trying to figure out how to handle almost the same problem. I'll try to describe more info:

I use netcoreapp1.0, RESTful services over WebAPI hosted on IIS. Frontend: angular2.

In my Startup.cs:

// this is not much important, you can organize builder in Configure method, calling app.UseCors()
public void ConfigureServices(IServiceCollection services)
{   
    services.AddCors(options =>
            {
                options.AddPolicy("AllowSpecificOrigin",
                    builder => builder.WithOrigins("http://localhost:37885")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            });
    services.AddMvc();  
    services.Configure<MvcOptions>(options =>
    {
        options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseCors("AllowSpecificOrigin");
    app.UseMvc();    
}

This code worked perfectly when I run it in Visual Studio. But as soon as I published my WebAPI project on IIS I got trouble: preflight request returned Status "Code:204 No Content", while POST and PUT requests returned "405 Method Not Allowed":

204 status for preflight CORS request

405 error for PUT request

It seemed like AllowAnyMethod() did not have any effect when app was hosted on IIS, because only GET, HEAD, OPTIONS, TRACE were allowed as we can see from the picture above.

To test this thing and to remove suspicions from angular and Web API, I created test script and ran it in Chrome developer console:

var xmlHttp = new XMLHttpRequest(); //returns a XMLHttpRequest object
xmlHttp.open('PUT', "http://localhost:27895/api/usergroups/58c624eb54d98519e85c5771", true);
xmlHttp.setRequestHeader('Content-Type', "application/json");  
xmlHttp.send(JSON.stringify({"id":"58c624eb54d98519e85c5771","Name":"Группа первооткрывателей"}));

I've got the same issue running this script from my angular client page. Than I ran this script from the same origin WebApi was hosted on (to check webAPI without COR). I've got an error, which told me that PUT method is not Allowed on site!

Finally, I found the solution: the problem was in WebDAV module on IIS, conflicted with my RESTful services. I removed WEBDAV module from my webAPI site On IIS and now it works perfect:

cross-origin put request running from my angular site returns 200 status now

To do this:

  1. choose you WebAPI site on IIS
  2. open "Modules"
  3. find and remove WebDAV option

Remove WebDAV option from Handler Mappings on IIS for your webApi site as well.

These topics can be useful if you want some more explaination about WEBDAV and Web API conflicts:

forum iis.net, forum asp.net


As it turned out, WebDav handler and module appears again in IIS after the next publish. So, to prevent site from doing this, modify your web.config of WebAPI application, like this:

<handlers>
   <remove name="WebDAV" />
</handlers>
<modules>
   <remove name="WebDAVModule" />
</modules>

this topic helped me to figure it out.

Community
  • 1
  • 1
Johnny Svarog
  • 1,125
  • 10
  • 17