Enable Cross Origin Resource Sharing (CORS) In ASP.NET Core

In this post, we will focus on how to enable CORS in ASP.Net Core application, get knowledge about CORS policy, and how we can share resources through different origins.

The following topics will be discussed.

  • What is CORS?
  • Create .NET Core WebAPI Application

    • Add Packages
    • Add Database Connection
    • Enable CORS

  • Publishing to IIS
  • Share Through .NET Core Sample Application

Introduction

First, let’s get introduced to CORS. According to Wikipedia, "Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the resource originated."

Get more details from docs.asp.net. Let’s get started with a sample application.

Create New Application

Open Visual Studio 2015, then go top menu. and Click > File > New > Project

Application

Choose Web API template.

Application

Finally, .Net Core Welcome page will appear. Read more about .NET Core.

Application

First, we need to add required packages to the sample application. Here, we have added those packages listed below in project.json file. After putting all those packages in our project config file, they will automatically be added to our application by IDE.

project.json

  1. //EntityFrameworkCore  
  2. "Microsoft.EntityFrameworkCore.SqlServer""1.0.1",  
  3. "Microsoft.EntityFrameworkCore.Tools""1.0.0-preview2-final",  
  4. "Microsoft.EntityFrameworkCore.SqlServer.Design""1.0.1",  
  5. "Microsoft.EntityFrameworkCore""1.0.1",  
  6. //Cross Origin Resource Sharing  
  7. "Microsoft.AspNetCore.Cors""1.0.0"  
Now, let’s add Database connection to our application. Open appsettings.json file. We have put down our database connection string here, as you can see from the below code section.

appsettings.json
  1. {  
  2.     "ConnectionStrings": {  
  3.         "dbConn""Server=DESKTOP-JAKRV2S;Database=PhoneBook;Trusted_Connection=True;MultipleActiveResultSets=true"  
  4.     },  
  5.     "Logging": {  
  6.         "IncludeScopes"false,  
  7.         "LogLevel": {  
  8.             "Default""Debug",  
  9.             "System""Information",  
  10.             "Microsoft""Information"  
  11.         }  
  12.     }  
  13. }  
After that, we need to call it in our application middle-ware in Startup.cs.
  1. publicvoidConfigureServices(IServiceCollection services) {  
  2.     //Add database services.  
  3.     varconnectionString = this.Configuration.GetConnectionString("dbConn");  
  4.     services.AddDbContext < PhoneBookContext > (options => options.UseSqlServer(connectionString));  
  5.     // Add framework services.  
  6.     services.AddApplicationInsightsTelemetry(Configuration);  
  7.     services.AddMvc();  
  8. }  
Now, we are going to add & enable CORS to our sample API application. Open Startup.cs file from Solution Explorer. As you can see, I have added the CORS service in ConfigureServices method to enable it getting called on run-time.

Here, we have also specified different CORS enabled policies by using CorsPolicyBuilder. You may test by enabling different types with this sample application.

Startup.cs ConfigureServices
  1. services.AddCors(  
  2.     options => options.AddPolicy("AllowCors",  
  3.         builder => {  
  4.             builder  
  5.             //.WithOrigins("http://localhost:4456") //AllowSpecificOrigins;  
  6.             //.WithOrigins("http://localhost:4456", "http://localhost:4457") //AllowMultipleOrigins;  
  7.                 .AllowAnyOrigin() //AllowAllOrigins;  
  8.                 //.WithMethods("GET") //AllowSpecificMethods;  
  9.                 //.WithMethods("GET", "PUT") //AllowSpecificMethods;  
  10.                 //.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;  
  11.                 .WithMethods("GET""PUT""POST""DELETE"//AllowSpecificMethods;  
  12.                 //.AllowAnyMethod() //AllowAllMethods;  
  13.                 //.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header"); //AllowSpecificHeaders;  
  14.                 .AllowAnyHeader(); //AllowAllHeaders;  
  15.         })  
  16. );  
Let’s separate the code with Origin.

With Origin

  • Allow Specific Origin
    builder.WithOrigins("http://localhost:4456")

  • Allow Multiple Origins
    builder.WithOrigins("http://localhost:4456", "http://localhost:4457")

  • Allow All Origins
    builder.AllowAnyOrigin()

With Methods

  • Allow Specific Methods
    builder.WithMethods("GET", "PUT", "POST", "DELETE")

  • Allow All Methods
    builder.AllowAnyMethod()

With Headers

  • Allow Specific Headers
    builder.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header")

  • Allow All Headers
    builder.AllowAnyHeader()

After that, we have enabled CORS for your application, using an extension method “UseCors“.

Startup.cs Configure
  1. //Enable CORS policy "AllowCors"  
  2. app.UseCors("AllowCors");  
Finally, the complete Startup.cs.
  1. publicclassStartup {  
  2.     public Startup(IHostingEnvironmentenv) {  
  3.         var builder = newConfigurationBuilder()  
  4.             .SetBasePath(env.ContentRootPath)  
  5.             .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)  
  6.             .AddJsonFile($ "appsettings.{env.EnvironmentName}.json", optional: true);  
  7.   
  8.         if (env.IsEnvironment("Development")) {  
  9.             // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.  
  10.             builder.AddApplicationInsightsSettings(developerMode: true);  
  11.         }  
  12.   
  13.         builder.AddEnvironmentVariables();  
  14.         Configuration = builder.Build();  
  15.     }  
  16.   
  17.     publicIConfigurationRoot Configuration {  
  18.         get;  
  19.     }  
  20.   
  21.     // This method gets called by the runtime. Use this method to add services to the container  
  22.     publicvoidConfigureServices(IServiceCollection services) {  
  23.   
  24.         //Add database services.  
  25.         varconnectionString = this.Configuration.GetConnectionString("dbConn");  
  26.         services.AddDbContext < PhoneBookContext > (options => options.UseSqlServer(connectionString));  
  27.   
  28.         // Add framework services.  
  29.         services.AddApplicationInsightsTelemetry(Configuration);  
  30.   
  31.         services.AddMvc();  
  32.   
  33.         //Add CORS services.  
  34.         //services.Configure<MvcOptions>(options =>  
  35.         //{  
  36.         // options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));  
  37.         //});  
  38.   
  39.         services.AddCors(  
  40.             options => options.AddPolicy("AllowCors",  
  41.                 builder => {  
  42.                     builder  
  43.                     //.WithOrigins("http://localhost:4456") //AllowSpecificOrigins;  
  44.                     //.WithOrigins("http://localhost:4456", "http://localhost:4457") //AllowMultipleOrigins;  
  45.                         .AllowAnyOrigin() //AllowAllOrigins;  
  46.   
  47.                     //.WithMethods("GET") //AllowSpecificMethods;  
  48.                     //.WithMethods("GET", "PUT") //AllowSpecificMethods;  
  49.                     //.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;  
  50.                     .WithMethods("GET""PUT""POST""DELETE"//AllowSpecificMethods;  
  51.                         //.AllowAnyMethod() //AllowAllMethods;  
  52.   
  53.                     //.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header"); //AllowSpecificHeaders;  
  54.                     .AllowAnyHeader(); //AllowAllHeaders;  
  55.                 })  
  56.         );  
  57.   
  58.     }  
  59.   
  60.     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline  
  61.     publicvoid Configure(IApplicationBuilder app, IHostingEnvironmentenv, ILoggerFactoryloggerFactory) {  
  62.         loggerFactory.AddConsole(Configuration.GetSection("Logging"));  
  63.         loggerFactory.AddDebug();  
  64.   
  65.         app.UseApplicationInsightsRequestTelemetry();  
  66.   
  67.         app.UseApplicationInsightsExceptionTelemetry();  
  68.   
  69.         app.UseMvc();  
  70.   
  71.         //Enable CORS policy "AllowCors"  
  72.         app.UseCors("AllowCors");  
  73.   
  74.     }  
  75. }  
MVC WebAPI

Here is the list of required namespaces.
  1. usingMicrosoft.AspNetCore.Mvc;  
  2. usingMicrosoft.AspNetCore.Cors;  
  3. usingCrossOrigin.WebService.Models.DbEntities;  
  4. usingMicrosoft.EntityFrameworkCore;  
API Controller

Here, we are applying specific CORS policies on APiController. It can also be applied on a per action basis, or globally, for all controllers.
  1. [EnableCors("AllowCors"), Route("api/[controller]")]  
  2. publicclassContactController: Controller {  
  3.     privatePhoneBookContext _ctx = null;  
  4.     publicContactController(PhoneBookContext context) {  
  5.         _ctx = context;  
  6.     }  
  7.   
  8.     // GET: api/Contact/GetContact  
  9.     [HttpGet("GetContact"), Produces("application/json")]  
  10.     publicasyncTask < object > GetContact() {  
  11.         List < Contacts > contacts = null;  
  12.         object result = null;  
  13.         try {  
  14.             using(_ctx) {  
  15.                 contacts = await _ctx.Contacts.ToListAsync();  
  16.                 result = new {  
  17.                     contacts  
  18.                 };  
  19.             }  
  20.         } catch (Exception ex) {  
  21.             ex.ToString();  
  22.         }  
  23.         return contacts;  
  24.     }  
  25.   
  26.     // GET api/Contact/GetContactByID/5  
  27.     [HttpGet("GetContactByID/{id}"), Produces("application/json")]  
  28.     publicasyncTask < Contacts > GetContactByID(int id) {  
  29.         Contacts contact = null;  
  30.         try {  
  31.             using(_ctx) {  
  32.                 contact = await _ctx.Contacts.FirstOrDefaultAsync(x => x.ContactId == id);  
  33.             }  
  34.         } catch (Exception ex) {  
  35.             ex.ToString();  
  36.         }  
  37.         return contact;  
  38.     }  
  39.   
  40.     // POST api/Contact/PostContact  
  41.     [HttpPost, Route("PostContact"), Produces("application/json")]  
  42.     publicasyncTask < object > PostContact([FromBody] Contacts model) {  
  43.         object result = null;  
  44.         string message = "";  
  45.         if (model == null) {  
  46.             returnBadRequest();  
  47.         }  
  48.         using(_ctx) {  
  49.             using(var _ctxTransaction = _ctx.Database.BeginTransaction()) {  
  50.                 try {  
  51.                     _ctx.Contacts.Add(model);  
  52.                     await _ctx.SaveChangesAsync();  
  53.                     _ctxTransaction.Commit();  
  54.                     message = "Saved Successfully";  
  55.                 } catch (Exception e) {  
  56.                     _ctxTransaction.Rollback();  
  57.                     e.ToString();  
  58.                     message = "Saved Error";  
  59.                 }  
  60.   
  61.                 result = new {  
  62.                     message  
  63.                 };  
  64.             }  
  65.         }  
  66.         return result;  
  67.     }  
  68.   
  69.     // PUT api/Contact/PutContact/5  
  70.     [DisableCors, HttpPut, Route("PutContact/{id}")]  
  71.     publicasyncTask < object > PutContact(int id, [FromBody] Contacts model) {  
  72.         object result = null;  
  73.         string message = "";  
  74.         if (model == null) {  
  75.             returnBadRequest();  
  76.         }  
  77.         using(_ctx) {  
  78.             using(var _ctxTransaction = _ctx.Database.BeginTransaction()) {  
  79.                 try {  
  80.                     varentityUpdate = _ctx.Contacts.FirstOrDefault(x => x.ContactId == id);  
  81.                     if (entityUpdate != null) {  
  82.                         entityUpdate.FirstName = model.FirstName;  
  83.                         entityUpdate.LastName = model.LastName;  
  84.                         entityUpdate.Phone = model.Phone;  
  85.                         entityUpdate.Email = model.Email;  
  86.   
  87.                         await _ctx.SaveChangesAsync();  
  88.                     }  
  89.                     _ctxTransaction.Commit();  
  90.                     message = "Entry Updated";  
  91.                 } catch (Exception e) {  
  92.                     _ctxTransaction.Rollback();  
  93.                     e.ToString();  
  94.                     message = "Entry Update Failed!!";  
  95.                 }  
  96.   
  97.                 result = new {  
  98.                     message  
  99.                 };  
  100.             }  
  101.         }  
  102.         return result;  
  103.     }  
  104.   
  105.     // DELETE api/Contact/DeleteContactByID/5  
  106.     [HttpDelete, Route("DeleteContactByID/{id}")]  
  107.     publicasyncTask < object > DeleteContactByID(int id) {  
  108.         object result = null;  
  109.         string message = "";  
  110.         using(_ctx) {  
  111.             using(var _ctxTransaction = _ctx.Database.BeginTransaction()) {  
  112.                 try {  
  113.                     varidToRemove = _ctx.Contacts.SingleOrDefault(x => x.ContactId == id);  
  114.                     if (idToRemove != null) {  
  115.                         _ctx.Contacts.Remove(idToRemove);  
  116.                         await _ctx.SaveChangesAsync();  
  117.                     }  
  118.                     _ctxTransaction.Commit();  
  119.                     message = "Deleted Successfully";  
  120.                 } catch (Exception e) {  
  121.                     _ctxTransaction.Rollback();  
  122.                     e.ToString();  
  123.                     message = "Error on Deleting!!";  
  124.                 }  
  125.   
  126.                 result = new {  
  127.                     message  
  128.                 };  
  129.             }  
  130.         }  
  131.         return result;  
  132.     }  
  133. }  
We can disable CORS by using attribute “DisableCors“. In this controller, we have applied “PUT” method to disable the CORS.

Publishing to IIS

We need to prepare our Server for ASP.NET Core application to host. Get more details on Publishing .NET Core Application. We have used localhost with assigning port 8081, to get accessed by our Sharing application.

http://localhost:8081

Application

Let’s browse our application by using http://localhost:8081 URL, as you can see our API is working with response of JSON data.

Application

Now is the time to access the shared resource. I have added an existing sample application to this solution. Given below is the simple change that I have made to access the resource via API from different origin.

Share Resource

Here, we have tried to access the resource through http://localhost:8081 but a server error occurred, as you can see below.



After enabling CORS we have successfully been able to access the shared resource through Web API.

Application

Output

Application

Source Code

I’ve uploaded the full source code to download/clone @github. Hope this will help.