59
votes

I am trying to enable CORS in .NET Core in this way:

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
                                                                    .AllowAnyMethod()
                                                                     .AllowAnyHeader()));     
        services.AddMvc();            
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseCors("AllowAll");

        app.UseMvc(routes =>
         {
             routes.MapRoute(
                 name: "default",
                 template: "{controller=Home}/{action=Index}/{id?}");
         });

    }
}

However, when I am sending a request to my app with Angular 2 I am getting the famous

"No 'Access-Control-Allow-Origin' header is present on the requested resource."

error message.

I am also using Windows Authentication + WebListener. If I am checking with postman the only response headers are:

Content-Length →3533 Content-Type →application/json; charset=utf-8 Date →Fri, 14 Oct 2016 12:17:57 GMT Server →Microsoft-HTTPAPI/2.0

So there must be still something wrong configured. Any proposals?

If I remove the outcommented line it works, but I need Windows Authentication :-(

        var host = new WebHostBuilder()
            .UseWebListener()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            //.UseWebListener(options => options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.NTLM)
            .Build();
10

10 Answers

64
votes

Assume you have the answer, but for the benefit of searchers, I had the same problem with the standard tutorial on .NET Core Cors.

One of the many errors encountered:

XMLHttpRequest cannot load localhost:64633/api/blogs. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:56573' is therefore not allowed access. The response had HTTP status code 500.

After playing around, the following code worked. Full class posted below to aid understanding of what goes where.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Cors.Infrastructure;

namespace NetCoreWebApiTesting
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

            if (env.IsEnvironment("Development"))
            {
                // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
                builder.AddApplicationInsightsSettings(developerMode: true);
            }

            builder.AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);

            services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling =
                                                            Newtonsoft.Json.ReferenceLoopHandling.Ignore);

            // ********************
            // Setup CORS
            // ********************
            var corsBuilder = new CorsPolicyBuilder();
            corsBuilder.AllowAnyHeader();
            corsBuilder.AllowAnyMethod();
            corsBuilder.AllowAnyOrigin(); // For anyone access.
            //corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url. Don't add a forward slash on the end!
            corsBuilder.AllowCredentials();

            services.AddCors(options =>
            {
                options.AddPolicy("SiteCorsPolicy", corsBuilder.Build());
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseApplicationInsightsRequestTelemetry();

            app.UseApplicationInsightsExceptionTelemetry();

            app.UseMvc();

            // ********************
            // USE CORS - might not be required.
            // ********************
            app.UseCors("SiteCorsPolicy");
        }
    }
}

To use it you can add the EnableCorsAttribute either on the controller or on the method. e.g.

[EnableCors("SiteCorsPolicy")]
[Route("api/[controller]")]
public class BlogsController : Controller
{

}

or

// POST api/value
[EnableCors("SiteCorsPolicy")]
[HttpPost]
public HttpResponseMessage Post([FromBody]Blog value)
{
    // Do something with the blog here....

    var msg = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
    return msg;

}

When I called this using the following code (using standard js/jQuery for easy of copy and paste), the communication stopped being rejected.

function HandleClick() {

    var entityData = {
        "blogId": 2,
        "url": "http://blog.com/blog1",
        "posts": [
        {
            "postId": 3,
            "title": "Post 1-1",
            "content": "This is post 1 for blog 1",
            "blogId": 2
        },
        {
            "postId": 4,
            "title": "Post 1-2",
            "content": "This is post 2 for blog 1",
            "blogId": 2
        }
        ]
    };

    $.ajax({
        type: "POST",
        url: "http://localhost:64633/api/blogs",
        async: true,
        cache: false,
        crossDomain: true,
        data: JSON.stringify(entityData),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (responseData, textStatus, jqXHR) {
            var value = responseData;
        },
        error: function (responseData, textStatus, errorThrown) {
            alert('POST failed.');
        }
    });
}
34
votes

This way works normally, just tried it on angular2 with .net core. The issue the OP is having is that this doesnt work with windows authentication. I am assuming the middleware for windows authentication is happening before a request comes through, in which case its breaking. Best bet would be to see if there is a way to enable the windows auth middleware after the cors middleware has processed in Configure.

Then the order would be

App.UseCors()

App.UseWindowsAuth()

App.UseMVC()

They must happen in this order for it to work.

public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
                                                                    .AllowAnyMethod()
                                                                     .AllowAnyHeader()));     
        services.AddMvc();            
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseCors("AllowAll");

        app.UseMvc(routes =>
         {
             routes.MapRoute(
                 name: "default",
                 template: "{controller=Home}/{action=Index}/{id?}");
         });

    }
14
votes

What the documentation misses, is the importance of .AllowAnyMethod(). If not present, the dreaded No 'Access-Control-Allow-Origin' will keep bugging you. In your code it's there, so I guess you missed setting the right header in jour client side application.

I Personally got it to work by allowing all:

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

And my Angular post function like:

post(model) {

    let headers = new Headers({
      'Content-Type':'application/json; charset=utf-8;' 
      ,'Accept':'*/*'
    });


    let options = new RequestOptions({ headers: headers });
    let body = JSON.stringify(model);

    return this.http.post(
      'http://localhost:58847/api/TestPost', body, options)
      .map((response: Response) => {
        let res = response.json();
        return res;
      }
    );
}

After that, you gradually work your way up by specifying origins etc.

14
votes

In ASPNET CORE 2.0, The following works for me

   public void ConfigureServices(IServiceCollection services)
    {

        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
        });
        services.AddCors(options =>
        {
            options.AddPolicy("AllowSpecificOrigin",
                builder => builder.WithOrigins("http://localhost:5000").AllowAnyHeader()
                .AllowAnyMethod());
        });

        services.AddMvc()
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {

        loggerFactory.AddConsole();
        loggerFactory.AddDebug(LogLevel.Information);

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        // Shows UseCors with named policy.
        app.UseCors("AllowSpecificOrigin");

        app.UseStaticFiles();
        app.UseAuthentication();


        app.UseMvcWithDefaultRoute();
    }
}
7
votes

Add this section in appsettings.json

"App": {
  "CorsOrigins": "http://yourdomain"
}

and

services.AddCors(options => {
  options.AddPolicy(DefaultCorsPolicyName, builder => {

   builder.WithOrigins(
     _appConfiguration["App:CorsOrigins"]
       .Split(",", StringSplitOptions.RemoveEmptyEntries)
       .Select(o => o.RemovePostFix("/"))
       .ToArray()
   ).SetIsOriginAllowedToAllowWildcardSubdomains()
    .AllowAnyHeader()
    .AllowAnyMethod()
    .AllowCredentials();
  });
});

Note: App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.

5
votes

You just need to add this in ConfigureService Method of StartUp Class

services.AddCors ();

and this in Configure Method of Startup Class and it will work fine then

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

There is nothing more to add to enable CORS in .Net Core

4
votes

I just fixed my problem with Cors in Core 3.1. I was following almost every example and documentation out there. Unfortunately nothing worked until I did .Build() for the builder inside the AddPolicy portion.

        services.AddCors(options => {
            options.AddPolicy(
                name: OrginPolicyKey, 
                builder => builder.WithOrigins("http://localhost:3000")
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .Build() // <--- This right here
            );
        });

Also, other people were mentioning about calling the UseCors(OrginPolicyKey) before the rest of your routing and UseMvc stuff. That is correct and I saw that Putting UseCors after the route part broke it. Below is how mine is setup.

        app.UseCors(OrginPolicyKey); // <--- First

        // Then routing stuff..
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints
                .MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}"
                );
        });

Who knew a builder needs to be built ;D

2
votes

The answer of @HockeyJ is right, but you can do something more concise if wanted.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    //Or if you want to chose what to include
    services.AddMvcCore()
            .AddCors()
            (...)
}


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //Cors
    app.UseCors(builder =>
    {
        builder.AllowAnyHeader();
        builder.AllowAnyMethod();
        builder.AllowCredentials();
        builder.AllowAnyOrigin(); // For anyone access.
        //corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url.
     });
}
2
votes

I encountered CORS issues in my application. I felt that I properly implemented the logic but was still getting presented with Access-Control-Allow-Origin 403 Error. I tried every setting mentioned above but nothing worked.

I later discovered that my issue wasn't CORS related. I implemented a custom attribute

[Route("v1/[Controller]")]
[ServiceFilter(typeof(MyCustomFilterAttribute))]
public class MySpecialListsController 

Calls made to the controller were properly making it to the method OnActionExecuting

public override void OnActionExecuting(ActionExecutingContext context)

The logic within the filter was throwing an exception and was presented as a CORS 403 error.

0
votes

this is actually is a bug in dotnet core.

try to add cors policy right in the "Configure" method.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseRouting();
        app.UseCors(option =>
            option.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                );
    }