简体   繁体   中英

CORS policy don't want to work with SignalR and ASP.NET core

I have a problem with my ASP.NET core API and my Angular Client. I want to implement SignalR to have a connection between API and Angular. The cors policy are already activated on our client and the API because we can already retrieve data from the API with our client. But the problem now is when I try to use SignalR I receive an error with CORS POLICY:

Access to XMLHttpRequest at ' http://localhost:50501/CoordinatorHub/negotiate ' from origin ' http://localhost:4200 ' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

But there's already cors policy inside the Startup.cs on our API and it's like that:

In the ConfigureServices method :

services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder => 
        builder.WithOrigins("http://localhost:4200/")
            .AllowCredentials()
            //.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .SetIsOriginAllowedToAllowWildcardSubdomains());
});

And inside the Configure method :

app.UseCors("AllowSpecificOrigin");

In our Client we just want to try to make a connection between the API and the client and it's like that:

this.hubConnection.start({withCredentials: false}).then(() => 
     this.hubConnection.invoke('send', 'Hello'));

Note this can be applied to .net core 3.1

As it's stated on microsoft docs it seems doesn't work docs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Preceding code ommitted.
    app.UseRouting();

    app.UseCors();

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

    // Following code ommited.
}

Warning

With endpoint routing, the CORS middleware must be configured to execute between the calls to UseRouting and UseEndpoints. Incorrect configuration will cause the middleware to stop functioning correctly.

But if you move your UseCors() in the first place your application will work as expected so the working code will be

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
                options.AddDefaultPolicy(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//place your useCors here 
    app.UseCors();
    app.UseRouting();


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

    // Following code ommited.
}

The accepted answer did not work for me so I decided to put down here what worked for me. In case someone stumbles across the same issue.

I was facing same issue in my local testing while playing around with signalR on Angular 9.

I solved it by switching my Asp NET Core (3.1) app URL from https to http. if you are using Visual Studio,

  1. just right click on project properties -> Debug.
  2. Uncheck Enable SSL

Asp网络核心项目

Also do not forget to change the port on your URL in angular App. So basically URL in angular app will be something like this

this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl("http://localhost:50782/hub").build();

whereas the relevant code in Configure method is something like this

app.UseHttpsRedirection();
app.UseStaticFiles();

   
app.UseRouting();
app.UseCors("_myAllowSpecificOrigins");

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
    endpoints.MapHub<ChatHub>("/hub");
});

and in your configureServices method I had following

    services.AddRazorPages();

    services.AddCors(options =>
        {
            options.AddPolicy("_myAllowSpecificOrigins",
                builder =>
                {
                    builder.WithOrigins("https://localhost:4200")
                           .AllowAnyHeader()
                           .AllowAnyMethod()
                           .SetIsOriginAllowed((x) => true)
                           .AllowCredentials();
                });
        });
    
   services.AddSignalR();

Hope this helps !

UPDATE

if you are just playing around with samples on your local machine you can also try to run chrome in security mode as mentioned here

on my mac I just simply ran command from terminal

open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security

With this you should be able to run your sample without CORS bothering

I solved my problem according to this link

Add this block code to service

services.AddCors(options => options.AddPolicy("CorsPolicy",
        builder =>
        {
            builder.AllowAnyHeader()
                   .AllowAnyMethod()
                   .SetIsOriginAllowed((host) => true)
                   .AllowCredentials();
        }));

and add this block code in configuring app

app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
        {
            routes.MapHub<General>("/hubs/general");
        });

try something like this in your startup configuration class:

app.Map("/CoordinatorHub/negotiate", map =>
{
    map.UseCors(CorsOptions.AllowAll);
    var hubConfiguration = new HubConfiguration 
    {
        // You can enable JSONP by uncommenting line below.
    // EnableDetailedErrors = true,
        // EnableJSONP = true

    };
    map.RunSignalR(hubConfiguration);
});

I had a similar problem that I struggled with for 6 hours.

It turned out that I had a slash at the end of my Origins.

So instead of:

.WithOrigins("https://aaa.azurewebsites.net/")

use:

.WithOrigins("https://aaa.azurewebsites.net")

Why the final slash isn't just stripped is beyond my understanding.

Recently i have face the same issue for .Net Core 3.1, Issue start when i deploy in Azure App service and lastly able to solve the issue use the following code.

I use the following code in ConfigureServices function on Startup.cs file

services.AddCors(options =>
        {
            var corsUrls = Configuration.GetSection("App:CorsOrigins").Value.ToString()
                      .Split(",", StringSplitOptions.RemoveEmptyEntries)
                             .Select(o => o.Trim('/'))
                             .ToArray();
            options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.WithOrigins(corsUrls)
                       .AllowAnyHeader()
                       .AllowAnyMethod()
                       .AllowCredentials();
            });
        });

Then add the following code in Configure function

app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
  {
    endpoints.MapControllers();
    endpoints.MapHub<WebhookHub>("/Webhook");
  });

Don't forgot to add the following section in appsetting.json file

"App": {
"CorsOrigins": "https://myservice.com" }

Tested on signalR in .Net Core 3.1+ and Angular 8+ versions and android 19+ api level and working on iOS devices too

.Net core code

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy", builder => builder.WithOrigins("http://localhost:4200")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                );
            });


            services.AddRazorPages();
            services.AddAccessTokenService();
            services.AddSignalR()
                 .AddHubOptions<ChatHub>(options => options.EnableDetailedErrors = true)
                 .AddJsonProtocol(options =>
                 {
                     options.PayloadSerializerOptions.PropertyNamingPolicy = null;
                  }); ;
            services.AddSingleton<IUserIdProvider, NameUserIdProvider>();

        }



public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();
            app.UseCors("CorsPolicy");

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapRazorPages();
                endpoints.MapHub<ChatHub>("/chathub");
            });

        }

--Angular code replace url and token(optional part) with and it's working--

public startConnection = () => {
  this.hubConnection = new signalR.HubConnectionBuilder()
                          .withUrl(this.url,{ accessTokenFactory: () => this.token},)
                          .build();

  this.hubConnection
    .start()
    .then(() => console.log('Connection started'))
    .catch(err => console.log('Error while starting connection: ' + err))
}

   ngOnInit(): void {
      this.startConnection();

  }

After doing a lot of research I also would like to share what I have faced and how I fixed it.

My scenario was; I deployed my .Net Core app on Azure App Services along with Azure SignalR configuration. Everything was working fine when I run both frontend and backend on my local machine. But when I deploy my app on azure services, I could not be able to connect due to this ../Hub/negotiate and cors issue.

How I fixed; First make sure you already enabled cors settings in your api as friends indicated here. I took my example signalR apps from Microsoft docs in this link . Finally I realized that in project examples the @aspnet/signalr@1.0.0 package is outdated and moved to @microsoft/signalr . And In my research I saw in some places that withCredentials should be set to false because by default this value is true and forces the connection to use SSL. My client app is running on local with http and trying to connect https connection. For more of this, refer to this link . In the old signalR npm package this value wasn't set, so as soon as I switched to the new one, withCredentials attribute activated and I set it false. All started working fine.

My final hub builder is like this;

var connection = new signalR.HubConnectionBuilder()
            .withUrl('https://**chat.azurewebsites.net/chat', {
                accessTokenFactory: () => 'InR5cCI6IkpXVCJ9.eyJpZCI6I',
                withCredentials: false
            }).build();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM