0% found this document useful (0 votes)
178 views19 pages

Enabling CORS in ASP - NET Core by Example - Code Maze Blog

Uploaded by

scottgurvey
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
178 views19 pages

Enabling CORS in ASP - NET Core by Example - Code Maze Blog

Uploaded by

scottgurvey
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 19

Want to kick start your web development in C#? Check out BLAZOR WEBASSEMBLY COURSE!

🔥
    SEARCH 

HOME BOOK V2 📙 BLAZOR WASM 🔥 GUIDES  WE ARE HIRING! ABOUT 

Enabling CORS in
ASP.NET Core
Posted by Code Maze | Updated Date Oct 8, 2021 | 24 

Want to build great APIs? Or become even


better at it? Check our Ultimate ASP.NET
Core Web API program and learn how to
create a full production-ready ASP.NET Core
API using only the latest .NET technologies.
Bonus materials (Security book, Docker
book, and other bonus files) are included in
the Premium package! 
In this post, we are going to talk about enabling CORS in
ASP.NET Core Web Applications.
To download the source code for this article, you can
visit our Enabling CORS in ASP.NET Core repository.

This post is divided into the following sections:


What Is CORS?
About Same-Origin and What it Means
What Is the Same-Origin policy?
Preflight Requests

Creating an Application Without CORS


Enabling CORS in ASP.NET Core Middleware
Enabling CORS in ASP.NET Core with Attributes
Configuring CORS Policy
How to Disable CORS

Before we understand how to enable CORS in ASP.NET Core


applications, we need to understand an important concept in
the web application security model called the Same-Origin
Policy.

What Is CORS?
Let’s learn what the term same-origin actually means first.

About Same-Origin and What it Means


Two URLs are considered to have the same origin if they have
the same URL scheme (HTTP or HTTPS), same hostname
(domain name), and same port number (the endpoint at which
applications talk to each other).


What Is the Same-Origin policy?
The Same-origin policy states that a Web browser will only
allow communication between two URLs if they belong to the
same origin. That is, the client app ( https://example.com )
cannot communicate with the server app
( https://example.net ) as they belong to a different origin.
This policy exists to isolate potentially malicious scripts from
harming other documents on the web.

But there are some cases where Cross-Domain scripting is


desired and the idea of the open web makes it compelling.

Cross-Origin Resource Sharing is a mechanism to bypass the


Same-Origin policy of a Web browser. Specifically, a server app
uses additional HTTP headers to tell a browser that it is fine to
load documents (from its origin) in a few selected client apps
(of different origin).

But how does CORS actually work?

Let’s have a look at the picture below. There is a client app


( https://example.com ) sending a GET request to a server
app ( https://example.net ) for some resource:


Thank you, your sign-up request
All modern browsers set the Origin header automatically, successful! Please check your em
which indicates the domain of the site is making the request. to confirm.

If the server allows Cross-origin requests from the Origin


( https://example.com ), it sets the Access-Control-Allow-
Origin header with its value matching the origin header’s
value from the request.

In another way, if the server doesn’t include this header, the


request fails. The browser shall receive the response data, but
this data shall not be accessible to the client.

That’s how a simple CORS request works.

Preflight Requests
Sometimes, instead of a simple GET request, a client may need
to send requests like PUT, DELETE, etc. For such requests, the
browser sends an additional request (an OPTIONS request)
called a Preflight request. This is done just before the actual
request to make sure that the original request succeeds. If it
does, the browser sends the actual request.

This diagram illustrates such a scenario:

A preflight request

Actual request

Creating an Application
Without CORS
In the demo, let’s create two projects. The first one is going to
be a Web API project, and the second one is going to be a
Blazor WebAssembly project.

Let’s create a Web API project that will be our server. Once we
create this project, we are going to modify the launchSettings.
json file:

{
"profiles": {
"CorsServerApp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": false,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5001;http
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" 
}
}
}
}
As you can see, this app will run on the https://localhost:5001
URI.

Next, let’s create a Client app. We are going to create a new


Blazor WebAssembly standalone project. Of course, we have
to modify the launchSettings.json file as well:

{
"profiles": {
"CorsClientApp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{
"applicationUrl": "https://localhost:5011;http
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

Okay. We have both a client and the server app running and
they belong to different origins. The server app will run on port
5001 and the client app on port 5011.

To make cross-origin requests, we first have to modify the


Program.cs file of the client’s app:

public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefau
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient

await builder.Build().RunAsync();
}

Here, we just set up the base address for the HttpClient, which
is the URI of our Web API.

Then, we have to open the Pages/FetchData.razor file, and


modify the @code part:

@code {
private WeatherForecast[] forecasts;

protected override async Task OnInitializedAsync


{
forecasts = await Http.GetFromJsonAsync<Weat
}

...
}

Since we already modified the base address of the HttpClient,


by adding this change, we want to send our GET request to the
https://localhost:5001/weatherforecast URI, which is
the exact address of the GET action inside the
WeatherForecast controller in the server app.

Since we haven’t enabled CORS on the server app, the


server app doesn’t set any headers and the browser
rejects the response.

So, if we start both applications, navigate to the client app, and


open the Fetchdata page, we are going to see the error
message:


So, we can see that the request is blocked by CORS policy and
our client app is not allowed to fetch the data from the
required resource.

Enabling CORS in ASP.NET


Core Middleware
Now that we have seen the Same-Origin policy in action, let’s
see how we can enable CORS in ASP.NET Core.

To do that, let’s open the Startup.cs file in the server app


and modify it:

public class Startup


{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }


private readonly string _policyName = "CorsPolic

public void ConfigureServices(IServiceCollection


{
services.AddCors(opt =>
{
opt.AddPolicy(name: _policyName, builder
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();

});
});

services.AddControllers();
}
public void Configure(IApplicationBuilder app, I
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

app.UseRouting();
app.UseCors(_policyName);

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

First, we create a private variable to hold the name of our


CORS policy. Then, in the ConfigureServices method, we
call the AddCors method that adds cross-origin resource
sharing services to the service collection. This method accepts
an Action delegate as a parameter where we can configure the
CORS options. For the CORS options, we call the AddPolicy
method, which adds a new policy to the configuration and also
accepts an Action delegate as a parameter where we can set
up the methods to build our policy.

With this policy, we enable access from any origin


AllowAnyOrigin , allow any header in a request
AllowAnyHeader , and allow any method AllowAnyMethod . 

We can agree that this policy is not the strict one, but it is a
basic setup that will remove the CORS issue for our client
application.

Also in the Configure method, we call the UseCors method


and pass the policy name to add the CORS middleware to the 
application’s pipeline. It is very important that we call this
method after the UseRouting method and before the
UseAuthorization method.
Now, with these changes in place, we can start both of our
apps and navigate to the FetchData page:

There we go. We have enabled CORS in our application and


removed the issue we were facing before.

Default Policies for CORS in ASP.NET Core


In the case where we don’t want to use multiple named
policies but a single default policy, we can replace the
AddPolicy method with the AddDefaultPolicy method:

services.AddCors(opt =>
{
opt.AddDefaultPolicy(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod(); 
});
});

As you can see, we are not providing the name for the policy.
Additionally, we don’t have to provide the policy name in the
UseCors method:

app.UseRouting();
app.UseCors();

app.UseAuthorization();

For the rest of the article, we are going to stick with the
named CORS policy configuration.

Enabling CORS in ASP.NET


Core with Attributes
If we only want to allow CORS requests to a selected few
methods, instead of enabling CORS at the entire application
level, we can also enable CORS at the controller level or at the
action level. To be able to do that, we have to use the
[EnableCors] attribute:

We can use just the [EnableCors] attribute on top of


the controller or the action, and it will implement a
default CORS policy
Or we can use the [EnableCors("Policy name")]
attribute, to apply a named CORS policy

By using the named policy with the [EnableCors] attribute,


we can apply different policies to different controllers or
actions.

So, in our example, if we want, we can add one more named


policy for the CORS configuration:

private readonly string _policyName = "CorsPolicy";


private readonly string _anotherPolicy = "AnotherCor

public void ConfigureServices(IServiceCollection ser


{
services.AddCors(opt =>
{
opt.AddPolicy(name: _policyName, builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
opt.AddPolicy(name: _anotherPolicy, builder
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});

services.AddControllers();
}

Also, we have to modify the Configure method:

app.UseRouting();
app.UseCors();

This time, we are not specifying the policy name since we are
using more than one policy in our application.

Finally, to see the [EnableCors] attribute in action, we are


going to modify the WeatherForecastController :

[EnableCors("CorsPolicy")]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => ne
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Lengt
})
.ToArray(); 
}

[EnableCors("AnotherCorsPolicy")]
[HttpGet("anotherPolicyExample")]
public IActionResult GetTempAboveLimit()
{
return Ok("This action is protected with another
}

As you can see for the first action, we are enabling CORS
using the old named policy – CorsPolicy. But for the other
action, we are using a new policy – AnotherCorsPolicy.

Okay, now we know how to apply different policies while


enabling CORS. But it is not a good practice to use two
different named policies that apply the same policy options. In
this situation, only one policy would be sufficient.

So, let’s see how we can configure different policy options and
make sense of using different named policies in our
application.

Configuring CORS Policy


We can use various options while adding policies to the CORS
configuration. 

Right now, for both policies, we are allowing any origin, any
header, and any method. But let’s say, we want to allow only
our client application to access the first GET action from the
WeatherForecast controller, and some other client (on port
5021) to access the second action:


public void ConfigureServices(IServiceCollection ser
{
services.AddCors(opt =>
{
opt.AddPolicy(name: _policyName, builder =>
{
builder.WithOrigins("https://localhost:5
.AllowAnyHeader()
.AllowAnyMethod();
});
opt.AddPolicy(name: _anotherPolicy, builder
{
builder.WithOrigins("https://localhost:5
.AllowAnyHeader()
.AllowAnyMethod();
});
});

services.AddControllers();
}

This time, we are using the WithOrigins method, which


accepts a params string[] origins as a parameter. This
means, if we want to allow access to multiple origins for a
single policy, we can just add multiple comma-separated URIs
as an argument: WithOrigins("First URI", "Second
URI") . 

Configuring CORS for Multiple


Subdomains
One more thing. When we want to allow access for a client that
has a main domain and multiple subdomains, we don’t have to
add all the URIs with subdomains as arguments. What we can
do is use the wildcard in the WithOrigins method followed
by the SetIsOriginAllowedToAllowWildcardSubdomains
method: 

opt.AddPolicy(name: _policyName, builder =>


{
builder.WithOrigins("https://*.code-maze.com")
.SetIsOriginAllowedToAllowWildcardSubdomains
});

By using the 
SetIsOriginAllowedToAllowWildcardSubdomains method,
we allow origins to match a configured wildcard domain when
evaluating if the origin is allowed.

Enabling CORS for Specific Methods


If we take a look at our controller, we can see that we have
only GET actions inside. Well, we can specify that as well in the
CORS configuration:

public void ConfigureServices(IServiceCollection ser


{
services.AddCors(opt =>
{
opt.AddPolicy(name: _policyName, builder =>
{
builder.WithOrigins("https://localhost:5
.AllowAnyHeader()
.WithMethods("GET");
});
opt.AddPolicy(name: _anotherPolicy, builder
{
builder.WithOrigins("https://localhost:5
.AllowAnyHeader()
.WithMethods("GET");
});
});

services.AddControllers();
}

Now, instead of AllowAnyMethod , we are using


WithMethods , which accepts params string[] methods as
a parameter. Of course, this means if we want to allow access
to multiple methods, we need to add them as multiple comma-
separated strings: WithMethods("PUT", "DELETE", "GET") .

Enabling CORS for Specific Headers


In the same way that we use the WithMethods method to
specify access for single or multiple methods, we can use the
WithHeaders method to allow specific headers to be sent in a
CORS request:

opt.AddPolicy(name: _anotherPolicy, builder =>


Copy
{
builder.WithOrigins("https://localhost:5021")
.WithHeaders(HeaderNames.ContentType, Header

});
.WithMethods("GET");

Additionally, when we want to expose some headers, we can
use the WithExposedHeaders method. For example, in our
Blazor WebAssembly Pagination with ASP.NET Core Web
API article, we create a pagination functionality on the Web
API’s side and add the required information inside the X-
Pagination header:

[HttpGet]
public async Task<IActionResult> Get([FromQuery] Pro
{
var products = await _repo.GetProducts(productPa
Response.Headers.Add("X-Pagination", JsonConvert
return Ok(products);
}

But for our client application to be able to access that


information inside the header, we have to expose it in the
CORS configuration:

opt.AddPolicy(name: _anotherPolicy, builder =>


{
builder.WithOrigins("https://localhost:5021")
.WithHeaders(HeaderNames.ContentType, Header
.WithMethods("GET")
.WithExposedHeaders("X-Pagination");
});


And that’s it for our CORS configuration.

Additional read: You can see the CORS in action with .NET Core
and Angular projects by reading the .NET Core tutorial.
How to Disable CORS
Finally, a small note on disabling CORS. Sometimes we need
to disable CORS on the action or the controller level.

To do that, we can use the [DisableCors] attribute:

[DisableCors]
[HttpGet]
public async Task<IActionResult> Get([FromQuery] Pro
{
var products = await _repo.GetProducts(productPa
Response.Headers.Add("X-Pagination", JsonConvert
return Ok(products);
}

That’s it for now. Let’s recap what we’ve learned.

Conclusion
Think of CORS as a relaxation attempt to the more restrictive
Same-Origin policy. On one side, there is a growing need for
security on the web. And on the other, there is a need to
integrate web services. CORS provides rich tools for our need
for an open and secure web, and ASP.NET Core allows us to
take advantage of CORS in our cross-platform web
applications.

Want to build great APIs? Or become even


better at it? Check our Ultimate ASP.NET
Core Web API program and learn how to
create a full production-ready ASP.NET Core
API using only the latest .NET technologies.
Bonus materials (Security book, Docker 
book, and other bonus files) are included in
the Premium package!
SHARE:   

 Subscribe  Login


J oin the discussion

{} [+] 

24 COMMENTS   Oldest

View Comments
© Copyright code-maze.com 2016 - 2022

You might also like