'NET5.0 Blazor WASM CORS client exception
I have a Blazor WASM app and a Web Api to get called by Blzor via HttpClient. Both programs run on the same machine (and also in production environment which should not be to exotic for a small business application!).
Calling the Web Api from the Blazor client result in a client CORS exception
Access to fetch at 'http://localhost:4040/' from origin 'https://localhost:5001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
which is the expected behavior for this case.
In an former api project I developed in PHP, that had the same client behavior, I can bypass the CORS exception by simply setting the response header e.g.
$response = new Response;
$response->setState(false, $route->command);
...
header("Access-Control-Allow-Origin: *");
echo $response;
Now I want this in my .net 5.0 Web Api. I found different docs in the internet to cope with that like in
https://docs.microsoft.com/de-de/aspnet/core/security/cors?view=aspnetcore-5.0 https://www.c-sharpcorner.com/article/enabling-cors-in-asp-net-core-api-application/ https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.withorigins?view=aspnetcore-5.0
and implemented it in my api
public class Startup {
//---------------------------------------------------------------------
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
//---------------------------------------------------------------------
public IConfiguration Configuration { get; }
//---------------------------------------------------------------------
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices
(
IServiceCollection services
)
=> services
.AddCors()
.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "api", Version = "v1"}) )
.AddControllers()
;
//---------------------------------------------------------------------
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure
(
IApplicationBuilder app,
IWebHostEnvironment env
)
=> app.
apply( _ =>
{
if (true) //(env.IsDevelopment())
{
app
.UseDeveloperExceptionPage()
.UseSwagger()
.UseSwaggerUI( c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "api v1") );
}
})
.UseCors( cors =>
cors
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed( _ => true )
.AllowCredentials()
)
.UseHttpsRedirection()
.UseRouting()
.UseAuthorization()
.UseEndpoints( e => e.MapControllers() )
;
//---------------------------------------------------------------------
}
Even tried to set the Response Header in the ApiController
[Route("/")]
[ApiController]
public sealed class ServertimeController : ControllerBase
{
//[EnableCors("AllowOrigin")]
[HttpGet]
public Servertime Get() {
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT");
return servertime();
}
}
The Blazor WASM client looks like
private async void onClick()
{
var response = await httpClient.GetFromJsonAsync<Servertime> ("http://localhost:4040");
message = response.servertime;
this.StateHasChanged();
}
But it still results in the client CORS exception. To bypass this for development I use the browser extension “CORS Unblock”, but this is not an option for deployment.
What would be the correct approach to avoid Blazor client exception, what do I miss?
Solution 1:[1]
@Dmitriy Grebennikov answer is also valid but it needs a little bit improvements to make this more secure.
in ConfigureServices
of Startup.cs
add the following code before services.AddControllers();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
builder.WithOrigins("https://localhost:44338")
.AllowAnyMethod()
.AllowAnyHeader());
});
Make sure that your url should not end with /
.
You can pass many url to WithOrigins
method.
finally in the Configure
method of Startup.cs
add the following line before app.UseAuthorization();
and after app.UseRouting();
app.UseCors();
The code should be working now.
Solution 2:[2]
Just add this to ConfigureServices method:
services.AddCors(options =>
{
options.AddPolicy("DevCorsPolicy", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
And this to Configure method:
app.UseCors("DevCorsPolicy");
Solution 3:[3]
For a solution in Blazor WASM, NOT on Serverside, this code snippet
Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestMode(
httpRequestMessage,
Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestMode.NoCors
);
will tell the local browser, which runs the local PWA, to not send CORS with the Request.
Code-Example (with call and used namespaces)
HttpRequestMessage httpRequestMessage = new HttpRequestMessage{
RequestUri = new Uri("[Adress]"),
Content = new StringContent(),
Method = HttpMethod.Post };
WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestMode(httpRequestMessage, BrowserRequestMode.NoCors);
HttpResponseMessage response = client.SendAsync(httpRequestMessage).Result;
--> the Version from "Dmitry Grebennikov" works. In my version, the Post isn`t async and the PWA throw an error.
Solution 4:[4]
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = new HttpMethod("GET"),
RequestUri = new Uri($"{site.BaseUrl}robots.txt")
};
request.Headers.Add("Accept", "text/plain");
request.SetBrowserRequestMode(BrowserRequestMode.NoCors);
var response = await client.SendAsync(request);
var txt = await response.Content.ReadAsStringAsync();
References
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Dmitry Grebennikov |
Solution 3 | |
Solution 4 | gjmwolmarans |