Reputation: 20565
I have the following middleware:
namespace TimeManagement
{
public class CorsMiddleware
{
private readonly RequestDelegate _next;
public CorsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers",
"Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorsMiddleware>();
}
}
}
And the following startup
class:
namespace TimeManagement
{
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.AddDbContext<WorkTimeContext>(opt =>
opt.UseInMemoryDatabase("WorkTime"));
services.AddDbContext<TimeManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TimeManagementContext")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddControllers();
}
// 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();
}
app.UseHttpsRedirection();
app.UseCorsMiddleware();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
Then I attempt to run https://localhost:5001/api/WorkTimes
GET and it returns without issues.
Now I am using an Angular
frontend and from there I am trying to post. As you may know, it sends an OPTIONS
first and here I get a CORS
error:
Upvotes: 2
Views: 3481
Reputation: 776
In here ,
is used by the server to return specific data set when valid credentials are sent via a GET HTTP method request.Therefore, in such a scenario, it makes no sense for the server to accept a POST request at that resource/URL, so it may respond with a 405(Method Not Allowed) status code when such a request is made.
The 405(Method Not Allowed) is an HTTP response status code indicating that the specified request HTTP method was received and recognized by the server, but the server has rejected that particular method for the requested resource.A 405 code response confirms that the requested resource is valid and exists, but the client has used an unacceptable HTTP method during the request.
This could happen in a few different circumstances:
Use the ASP.NET CORS middleware as below instead of custom middleware.(Asp.Net Core v3.0 sample code)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseCors(cor=> cor
.AllowAnyHeader()
.WithOrigins("http://localhost:4200","https://localhost:4200"));
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Upvotes: 1
Reputation: 2264
Cors errors can be very trick. Sometimes the browser returns this erros without really call your api. So first step you need to be sure that the browser call your API. To do this I usually add a dumb inline middleware and put a breakpoint in it. You could add a logger to it too.
The dumb middleware sample:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
// The others middlewares.
}
Now that you know if the problem is in your browser or in your app you can what can you do?
1) If the problem is in your browser, follow the instruction from @Eldho answer to enable it.
2) If the problem is in your app please read the rest of my answer.
Middlewares are executed in the same sequence you call it in Configure method.
Maybe HttpsRedirection
is returning this error. (Big maybe here)
You can try declare your custom app.UseCorsMiddleware()
before HttpsRedirection
. But I suggest you to use Asp.net Cors Middlewares that already exists and works fine. Why reinvent the wheel?
This is a sample of Asp.Net Core v2.1 Cors Middleware
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("Any",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("Any");
// The others middlewares.
}
Another approach (only for development) is to use SPA Middleware to forward the requests your SPA. This way your angular app and your Asp.Net app will answer on the same port of localhost and chrome will not block any. But it just work as temporary solution. It is not recommended to use this in production.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("Any");
// The others middlewares.
if (env.IsDevelopment())
{
app.UseSpa(spa =>
{
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
});
}
}
Upvotes: 0
Reputation: 8301
chrome doesn't support this.
Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Solution 1 [Temporary Development Solution]
chrome://flags/#out-of-blink-cors
Disable the out-of-blink-cors
flag by copying and pasting that address into the address bar of Chrome followed by [enter]. In the page that opens you'll see a highlighted so-called 'flag' (experiment). Disable it and restart Chrome
(Edit: previously I said to enable the flag but only disabling seems to work)
In many cases that solves the issue. You can upvote this feature on chrome here
Solution 2 (Recommended)
Create your api under in the sub-domain
your api url will be http://localhost:4200/api/YourEndpoint
Here
Voyage is our angular application.
Under it Api where we host our API so which will be under a same domain so CORS policy is not violated.
Upvotes: 0
Reputation: 15015
You need to send status code 200 for CORS preflight request, which your middleware is not setting right now.
Why don't you just use the ASP.NET CORS middleware which handles this? ASP.NET CORS Middleware
Upvotes: 2
Reputation: 6528
Can you try putting the following in web.config:
<httpHandlers>
...
<add path="*" verb="OPTIONS" type="System.Web.DefaultHttpHandler" validate="true"/>
</httpHandlers>
Upvotes: 0