Prologue

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources… “

- Cross-Origin Resource Sharing (CORS)

CORS error is quite common if we use front-end and back-end separation, and it could be really annoying. So in this post, I’d like to introduce to you a practical way to handle this in ASP.NET backend with Axios in the front end.


1. Front End

Well, I guess front end actually does nothing with CORS problems, but here I’ll still show you some occasions that may encounter CORS errors.

If nothing for CORS is configured in the backend, any requests will likely run into CORS error. Even if you configured some, you may still find that cookies 🥠 are still blocked by CORS, and backend will not be able to use them.

Well, you should know about Axios. For its configuration, you usually need a baseURL for convenience. And if you want to enable cookies, you also need to add withCredentials option.

1
2
3
4
axios.create({
withCredentials: true,
baseURL: 'http://localhost:5168/api/'
});

And… I guess there’s no more for front end.


2. Back End

2.1 Project Structure

First, you should have your ASP.NET Core Web API project created by Visual Studio. As for the project structure, you can refer to my another post.

2.2 NuGet Dependency

We need this NuGet package to enable CORS policies.

image-20230718174422855

2.3 Add CORS Policies

To make options more flexible, it is recommended to add an entry in appsettings.json. Of course, it may vary form override files.

1
2
3
4
5
6
7
8
9
10
11
12
13
{
// ...
"CorsOptions": {
"Enable": true,
"AllowAny": false,
"Origins": [
"http://badge.tonys-studio.top",
"http://www.tonys-studio.top:66",
"http://82.156.2.152:66",
"http://localhost:66"
]
}
}

Then, we can simply create a class to represent this option.

1
2
3
4
5
6
7
8
9
public class CorsOptions
{
public const string CorsSection = "CorsOptions";
public const string CorsPolicyName = "DefaultPolicy";

public bool Enable { get; set; } = false;
public bool AllowAny { get; set; } = true;
public List<string> Origins { get; set; } = new List<string>();
}

Finally, in our Startup.cs, add CORS policy. Here I only showed lines that essentially related to CORS configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
var corsOptions = new CorsOptions();
Configuration.GetRequiredSection(CorsOptions.CorsSection).Bind(corsOptions);
if (corsOptions.Enable) {
services.AddCors(options => {
options.AddPolicy(
name: CorsOptions.CorsPolicyName,
policy => {
if (corsOptions.AllowAny) {
policy.AllowAnyOrigin();
} else {
foreach (var origin in corsOptions.Origins) {
policy.WithOrigins(origin);
}
}
policy.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials(); // if cookies needed
});
});
}
}
}

For the full context of Startup.cs, please check out this Thoughts on Basic Structure of ASP.NET.

If you need cookies feature, and your front end request has withCredentials set to true, you have to use AllowCredentials() to make response carry Access-Control-Allow-Credentials header.

If you use AllowCredentials(), then you can not use AllowAnyOrigin(). For detailed reason, please check out here:

2.4 Use CORS Policies

Usually, it is sufficient to apply CORS policy in global scope. And this is it, just specify the name of the CORS policy you want to use.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Startup
{
// ...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseRouting();
// ...
app.UseCors(CorsOptions.CorsPolicyName);
// ...
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapSwagger();
});
}
}

Middlewares must be called in the right order, or some unexpected error may happen!

For more information on ASP.NET middleware pipeline order, please refer to its official document:

And, so nice are we that we have brought the essential image here. 😉

Tada! 🥳 Now your backend should be able to handle CORS requests.


Epilogue

As the project moving on, I’m even more attracted by ASP.NET Core framework.😍 Its elegance, clarity touched me. And of course, with Visual Studio as the ULTIMATE IDE in the universe. 🤩