CORS in .NET 6.0 web api - c#

I have a React app calling a .NET 6 Web API using Axios.
In the program.cs file, I have added builder.Services.AddCors and app.UseCors as below.
But I still get CORS error and 404 preflight.
The method used to works in .NET 5 Web Api.
Is there anything we need to set for .NET 6 Web Api ?
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
<removed>
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors();
// Add services to the container.
<removed>
// App settings
<removed>
<removed>
builder.Services.AddHttpContextAccessor();
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
});
// AutoMapper
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
<removed>
// Firebase
<removed>
var app = builder.Build();
The CORS registration is
app.UseCors(x => x.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("https://our-react-site.com"));
And the rest of the code
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

The CORS docs explain that UseCors middleware needs to be called in the correct order.
UseCors must be called in the correct order. For more information, see Middleware order. For example, UseCors must be called before UseResponseCaching when using UseResponseCaching.
The Middleware Order section shows that UseCors needs to be called after redirection and routing and before authentication and authorization.
In your code you'll have to call UseCors after UseHttpsRedirection and right before UseAuthentication :
app.UseHttpsRedirection();
app.UseCors(x => x.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("https://our-react-site.com"));
app.UseAuthentication();
The documentation example shows this:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Another difference is that the doc example creates at least one named policy and uses UseCors to apply this policy.

If you're using UseMiddleware, UseCors must be specified before it e.g.
var app = builder.Build();
app.UseCors(policy => policy.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(origin => true)
.AllowCredentials());
app.UseMiddleware<ApiKeyMiddleware>();

added this to my program.cs file in .NET 6.0 web api
app.UseCors(options => options.AllowAnyOrigin());

You might be blocking the OPTIONS http verb in IIS. Check the "HTTP Verbs" Tab in Request Filtering settings in your IIS. Remove the highlighted option as shown in the image from the link below.
IIS Request Filtering

Related

Not able to route to API in Blazor Server app

I’m brand new to Blazor and I’m trying to learn by converting an old website/web API project into a .Net 6 Blazor Server app where I plan to have both the UI and the API in the same application. I created a Controllers folder and added a controller called ApiController. I also set up Entity Framework and created my Entity classes for my SQL database tables. I’ve added the first HTTPGET route and tried hitting it through Postman to see if it will work. However, I keep getting a message that the page can not be found.
I thinking I need to add something to the Program.cs to let it know that I’m wanting to use APIs and Routing but, in my research, I’m not finding what I’m missing or what needs to be added. Most examples want to use a WASM project which probably has the API and Routing information built in.
This is the URL I'm trying to hit.
https://localhost:7168/api/usersadmin/GetAppNames
ApiController.cs
using Microsoft.AspNetCore.Mvc;
using UsersAdmin_AS.Data;
namespace UsersAdmin_AS.Controllers
{
[Route("api/UsersAdmin/[action]")]
[ApiController]
public class ApiController : ControllerBase
{
[HttpGet]
[Route("GetAppNames")]
public List<string> GetAppNames()
{
//logger.Info("GetAppNames");
List<string> listAppNames = new List<string>();
try
{
var dataManager = new DataManager();
listAppNames = dataManager.GetAppNames();
}
catch (Exception ex)
{
//logger.Error("ERROR: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
throw;
}
return listAppNames;
}
}
Program.cs
using UsersAdmin_AS.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Replace [Route("api/UsersAdmin/[action]")] with [Route("api/UsersAdmin/[controller]")]
and comment out [Route("GetAppNames")] in your controller.. Your swagger should show GetAppNames endpoint
I found this post and it fixed my issue.
https://stackoverflow.com/questions/70583469/host-web-api-in-blazor-server-application
This is the route I used at the top of the controller.
[Route("api/UsersAdmin/")]
I used this as my specific route.
[HttpGet]
[Route("GetAppNames")]
I added the builder.Services.AddControllers(), commented out the app.MapBlazorHub() and app.MapFallbackToPage("/_Host"). I then added the app.UseEndpoints() function.
Here is my updated Program.cs file.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using UsersAdmin_AS.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddControllers();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
//app.MapBlazorHub();
//app.MapFallbackToPage("/_Host");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapFallbackToPage("/_Host");
});
app.Run();

This localhost page can’t be found Asp.Net 6.02

Db Configuration
Program.cs
using FirstApp.DataAccessLayer.Infrastructure.IRepository;
using FirstApp.DataAccessLayer.Infrastructure.Repository;
using FirstApp.DataAccessLayer;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Add service to the razor pages
builder.Services.AddRazorPages();
//Add Service to the Repository
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
// Register Context File
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
// Idenitity Service
builder.Services.AddDefaultIdentity<IdentityUser>
().AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios,
see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
//pattern: "{controller=Home}/{action=Index}/{id?}");
pattern: "{area=Clint}/{controller=Home}/{action=Index}/{id?}");
app.Run();
but did not work show the error i can't understand
this error show
error show
but did not work show the error i can't understand
this error show
but did not work show the error i can't understand
this error show
but did not work show the error i can't understand
this error show

How to use AzureAd for only an Area (Admin) and regular Identity for root (User) in .net 5

I need to Authenticate users by different schemes for different Areas in my .net 5 mvc app. Here is the boiler plate code for AzureAD template;
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name : "areas",
pattern : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});
}
I need to use AzureAD for Admin area and Identity (auth with a DB server basically) for the root area, how do I do that, is it even possible? (without manual labor)
Yes, it is possible using MSAL only on admin side and Identity framework for non-admin users.
You can configure the MSAL in your .NET core application. Learn more here.
In your Startup.cs class you need to update configure method meaning you need to setup the middleware for authentication.
Learn more about MSAL+ Microsoft.Identity.Web here.

SignalR Access to fetch has been blocked by CORS

I am currently following this basic signal R tutorial.
But because I want to use it in an existing project I split it up. The Hub is inside a different project than the client. Therefore the IP address is different. Inside the configuration of the Hub I of course enabled cors:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
services.AddSignalR();
//other configuration code
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env){
app.UseRouting();
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<LiveUpdating.ChatHub>("/chatHub");
});
}
However when I now try to connect to the chatHub in my client (setup is exactly the same as in the link above except that I changed the connection to var connection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44316/chatHub").build(); ) I get this error:
Access to fetch at 'https://localhost:44316/chatHub/negotiate?negotiateVersion=1' from
origin 'https://localhost:44341' has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin'
header in the response must not be the wildcard '*' when the request's credentials mode
is 'include'.
Shouldn't this normally work, when I add the app.UseCors as seen above. Because for all my other Rest Controllers it works fine.
Replacing the app.useCors with
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true)
.AllowCredentials());
fixes the bug

Overriding global CORS policy with a different policy for signalR end point

I have a global CORS policy which is applicable for all the endpoints but I want to override this policy for the signalR hub end point.
Here is my ConfigureServices method which has a global CORS policy which I cant modify
public void ConfigureServices(IServiceCollection services)
{
// some piece of code before adding CORS
services.AddCors(o =>
{
o.AddDefaultPolicy(p =>
{
p.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// some piece of code after adding CORS
}
Here is the Configure method
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
app.UseCors();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endPoints =>
{
endPoints.MapControllers();
endPoints.MapHub<NotificationHub>("/notificationHub")
.RequireCors((builder) =>
{
builder
.WithOrigins(_configuration.GetValue<string>("Settings:ClientAppUrl"))
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
}
As it is clear that I have overwritten the CORS policy for the particular endpoint of signal which is /notificationHub.
I am getting the same CORS error in the browser as I was getting before adding the CORS policy for the /notificationHub/negotiate
Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow->Credentials' header in the response is '' which must be 'true' when the request's credentials mode is >'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the >withCredentials attribute.
Also please note that if I add AllowCredentials() method in the global CORS policy then signalR works properly but my objective here is to add the new CORS policy only for the signalR endpoint.
I am not using OWIN CORS, it is just Microsoft.AspNetCore.Cors.
I have found the fix for this. It is simple but often ignored.
The order of middleware matters here a lot. By swapping the below two middleware, I got it working.
OLD
app.UseCors();
app.UseRouting();
NEW
app.UseRouting();
app.UseCors();
If anyone facing this issue, try doing this. It would definitely work.
This doc from Microsoft supports this claim.

Categories

Resources