0

I have been struggling with this issue for a while now. I have middle-ware on my .NET Core web API that will send a user friendly error message based on the error code returned by my SQL Server.

This works perfectly in Postman and when I disable same origin policy for Chrome From Here

So this is pretty solid evidence that it is a CORS issue. After going through many posts on issues, I still have not been able to solve the problem.

QUESTION:

If I add the Allow-Control-Allow-Origin extension in Chrome here, everything works as expected. Are all users of my application going to need this installed on their browsers to receive proper errors on the front-end? This is my biggest concern. Here is my configuration below:

Policy in Web API Startup

app.UseCors(builder => builder
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());

I have it registered before MVC

services.AddCors();
services.AddMvc();

This is my method in Angular

  addNewPeopleCategory(
    personCategory: CreatePeopleCategory
  ): Observable<CreatePeopleCategory> {
    return this.http
      .post<CreatePeopleCategory>(this.url + "/create", personCategory)
      .pipe(catchError(this.handleErrorUpdate.bind(this)));
  }

This is my Error Handling method in Angular

 private handleErrorUpdate(errorResponse: HttpErrorResponse) {
    if (errorResponse.error instanceof ErrorEvent) {
      console.log("Client Side Error: ", errorResponse.error.message);
    } else {
      console.log("Server Side Error: ", errorResponse);
    }

    this.openSnackbar(errorResponse.error);
    return throwError(
      "There is an issue with the service. Please try again later.
    );
  }

When CORS are not disabled

enter image description here

When CORS are disabled in Chrome

enter image description here

sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
CAlex
  • 806
  • 8
  • 21
  • 1
    The reason the browser is sending two requests is that the first request is a CORS preflight OPTIONS request. And the 204 response code the server is sending back for that is fine, so that preflight succeeds because the response also includes the necessary Access-Control-Allow-\* headers. But the POST request from your frontend code fails with a 400 error — apparently because the request isn’t in the format the server expects. But your frontend code can’t access that response — because the server (like most servers) doesn’t add the Access-Control-Allow-\* headers to 4xx errors. – sideshowbarker Dec 08 '18 at 22:51
  • 2
    The gist of it is, if you want your frontend code to be able to catch 400 errors and do specific handling for them, then you need for the server to add the Access-Control-Allow-Origin header to 4xx responses. But anyway as far as what end users of your frontend application see, you don’t want to expose that 400 error to them anyway — because the cause of that 400 error is that your frontend code is sending a bad request, and there’s nothing an end user of your application could do to fix that, so it’s not clear what the point would be in trying to expose any info about that error to them. – sideshowbarker Dec 08 '18 at 22:59
  • @sideshowbarker So, I don't want the user to see the 400 Bad Request. I want them to see the error message created by the server. In my example above, the user is trying to create a duplicate category. This is caught by my middleware because it is a SQL server error, specifically SQL Error Code: 2601. Error code 2601 is a case that I have written a specialized message to be sent back as a response to the API call. It is just a string that gets sent to the Angular UI and displayed in a snackbar for the user. Since I am technically sending the error string back to the user, should I not use 400? – CAlex Dec 08 '18 at 23:13
  • 1
    If you use a 400 or any 4xx — anything other than a 2xx — then you need to configure the server to include the Access-Control-Allow-Origin in the response. By default the server won’t add the Access-Control-Allow-Origin header to 4xx responses. – sideshowbarker Dec 08 '18 at 23:30
  • Thank you for the great explanation, I didn't mean to make you repeat yourself at the end there, sorry! I have a way better understanding of whats going on now. In my post above, I thought what I was doing in the startup.cs of my API was supposed handle what you are telling me. From all the posts I have read, it should add the Access-Control-Allow-Origin in every response I make. Am I mistaken? Is that not the proper solution? – CAlex Dec 09 '18 at 00:51
  • 2
    You should add the Access-Control-Allow-Origin header to every response, yes. But the code shown in the question isn’t causing it to be added to 4xx error responses. That code is likely only causing it to be added to 2xx success responses. With most servers, if you want to make the server add custom headers to 4xx error responses, you need to do some special configuration in addition to whatever configuration you’d normally do to add headers to responses. So you probably want to do some research into the server docs and other questions+answers here at Stack Overflow to figure out how to do it. – sideshowbarker Dec 09 '18 at 01:11
  • @sideshowbarker Thank you for your help. I set my custom exceptions to only return 200 responses, even if it was really a 400 or 500, and it still was giving me the same issue. This led me to believe that it was the middleware itself that was stripping the Access-Control-Allow-Origin header away. Removing this line solves the issue, context.Response.Clear(); Everything is now working as expected. Here is the link to the tutorial for anyone else, [link](https://blogs.msdn.microsoft.com/brandonh/2017/07/31/using-middleware-to-trap-exceptions-in-asp-net-core/) – CAlex Dec 09 '18 at 02:08
  • 1
    Please consider posting the details of your solution as an answer — so that other Stack Overflow users who run into the same problem in the future will be able to find your answer to help them solve their problem. – sideshowbarker Dec 09 '18 at 02:47

1 Answers1

1

The issue was not with the way I was handling CORS on the server, but rather with the middleware I have been using for error handling.

I followed this tutorial here and it works quite well. The issue was this line in the middleware class itself:

context.Response.Clear();

Removing this line immediately fixed my CORS issues. Someone who commented at the bottom of the post tipped me off about it. From what I am gathering, this line would clear the CORS headers from the response, and then re-assign my specified status code and content type.

You will want to leave everything else in the class the same.

CAlex
  • 806
  • 8
  • 21