Jan 02 2024 09:57 AM - edited Jan 02 2024 09:59 AM
I created a PATCH method in an ASP.NET Core Web API like this:
#region Patch /// <summary> /// Patch TableName by id. /// </summary> // PATCH BY ID: /TableName/patch/{id} [HttpPatch("[action]/{id}", Name = "PatchTableNameById")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [SwaggerOperation( Summary = "Patch Table Name by id", Description = "This can be used to modify any table name record", OperationId = "PatchTableNameById", Tags = new[] { "Patch" } )] public async Task<IActionResult> Patch(string id, [FromBody] JsonPatchDocument<TableName> patchDoc) { if (patchDoc != null) { var tablename = await context.TableName.SingleOrDefaultAsync(x => x.Id.ToString() == id); if (tablename == null) return NotFound(); patchDoc.ApplyTo(tablename); context.Entry(tablename).State = EntityState.Modified; if (!ModelState.IsValid) { return BadRequest(ModelState); } await context.SaveChangesAsync(); return new ObjectResult(tablename); } else { return BadRequest(ModelState); } }
This works perfectly fine when I call it using Postman or directly using Swagger. However in my Blazor client I get an error when it is called. I have tried using httpclient, RestSharp and now Flurl.
The error returned when using the Developer Tools console to review the log is:
Access to fetch at 'http://localhost:5259/SharedServices/Commands/TableName/patch/2bd4e0f3-974a-4794-bb63-b0ce00ba5147' from origin 'http://localhost:5265' has been blocked by CORS policy: Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response.
Here is my CORS policy in the Web API. It is called before anything else adding services.
builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigins", builder => { builder.WithOrigins("http://localhost:56075", "http://localhost:5265", "https://localhost:7235").AllowAnyHeader().WithMethods("PATCH"); }); });
I have tried various combinations here including of allowing all methods, headers, and origins. In other words opening it wide up which isn't a great security tactic anyways.
Here is my client side code for the call.
public async Task Patch(string id, JsonPatchDocument<TableName> patchDoc) { var url = "http://localhost:5259/SharedServices/Commands/TableName/patch/" + id; var resultStr = await url.WithHeader("Content-Type", "application/json-patch+json").PatchJsonAsync(patchDoc) .ReceiveString(); }
I have tried about every online suggestion to fix this. One problem is there are a lack of issue reports for later versions of asp.net -- post addition of addCORS. I have tried various browsers thinking this maybe a browser issue but no luck there either. Is this possibly a bug in asp.net core cors? I am also using Steeltoe. Is it possible it is interfering with this?
Is there any way to turn off a preflight request or modify it?
I tried to use various clients such as httpclient, restsharp, flurl. Also tried using a PUT and got the same issue. I have also tried various browsers. The expected result is a successful unblocked call to my web api method.
Thanks for any help you can give!
Jan 10 2024 06:22 AM
I have tried to solve and summarise your issue for the PATCH method not being allowed in Blazor due to CORS restrictions, let me know if this helps.
Understanding the Issue:
Resolving the Issue in Blazor:
Configure CORS in Startup.cs:
services.AddCors(options =>
{
options.AddPolicy("AllowPATCH",
builder => builder.WithOrigins("http://localhost:5000") // Adjust origins as needed
.AllowAnyMethod() // Or explicitly list PATCH
.AllowAnyHeader();
});
app.UseCors("AllowPATCH");
Enable CORS in ASP.NET Core Web API (if applicable):
[EnableCors("AllowPATCH")]
[HttpPatch]
public IActionResult PatchData()
{
// ...
}
Jan 16 2024 07:51 AM
@JaiminsoniThank you for the helpful suggestions. This turned out to be a conflict with Steeltoe. When using AddAllActuators the Steeltoe code is adding it's own CORS policy overriding anything that I was setting up. When adding each actuator separately then it works. This was a tough one to solve. I was only able to do that by looking at the CORS policy collection and noticing there was an additional one above mine.