How can I stop Swashbuckle adding an unwanted (and unspecified) Base URL? - c#

I have an odd problem where my API project has started inserting a base URL ("/swagger") seemingly overnight with no changes to the code. The base URL only appears when I am working on the project locally, when it is deployed to an Azure app service everything is normal. See image for the problem:
In startup my swagger setup looks like this:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My AppName API", Version = "v1" });
c.OperationFilter<SwaggerTokenParameter>();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("../swagger/v1/swagger.json", "V1 Docs");
});
...
}
I have tried recloning the project onto my machine but the problem has persisted, I have also tried manually setting the RoutePrefix:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("../swagger/v1/swagger.json", "V1 Docs");
c.RoutePrefix = string.Empty;
}
This doesn't help - it just breaks the UI and the definition still contains the base url:
{"swagger":"2.0","info":{"version":"v1","title":"My AppName API"},"basePath":"/swagger",...

Thanks to this answer I was able to come up with a solution. I still don't understand what changed to add in the base URL though or why it doesn't happen in the App Service.
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
swaggerDoc.BasePath = null;
});
});

Related

No service for type ' Microsoft.AspNetCore.Components.WebAssembly.Authentication.BaseAddressAuthorizationMessageHandler' Error

I am currently working on a project that consists of sub-projects such as WebApp, API, and Client class library. (The project structure is shown below).
Project Solution Structure
Although the project is a web-based project, it uses windows Identity as authentication identity since it is an internal application. I implemented the authorization policy of the WebApp project without any problems by following the steps in the implementation_link.
Now I can control access using DataAnnotation in WebApp (ex. [Authorize(Roles = "Admin"]). If I add Authorization control on the API side, WebApp cannot access this API. This is because of HttpContext.User is null. I found the solution to this problem solution_link. I adapted this solution to the project as below:
ServiceCollectionExtensions.cs in WebApp project:
public static IServiceCollection AddAuraServices(this IServiceCollection serviceCollection, IConfiguration configuration)
{
serviceCollection.AddTransient<IModelDatabaseNamesProvider, StandardCasingModelDatabasesNamesProvider>();
serviceCollection.Configure<RouteOptions>(routeOptions =>
{
routeOptions.ConstraintMap.Add(ModelDatabasesNameConstraint.Name, typeof(ModelDatabasesNameConstraint));
});
serviceCollection.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
serviceCollection.AddScoped<IModelMetadataProvider>(serviceProvider =>
{
var httpContext = serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
var modelName = httpContext.Request.RouteValues["model-name"].ToString();
return new ModelMetadataProvider(modelName);
});
DateOnlyTypeConverter.AddAttributeToType();
serviceCollection.AddHttpClient<UploadRulesClient>("ServerAPI", (httpClient) =>
{
httpClient.BaseAddress = new Uri(configuration["AuraApiClient:BaseAddress"]);
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
serviceCollection.AddHttpClient<ScenarioZipFilesClient>("ServerAPI",(httpClient) =>
{
httpClient.BaseAddress = new Uri(configuration["AuraApiClient:BaseAddress"]);
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
serviceCollection.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("ServerAPI"));
var jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
ClientJsonResponse.Configure(jsonSerializerOptions);
serviceCollection.AddSingleton(jsonSerializerOptions);
serviceCollection.AddAuraDropzoneConfig(configuration);
return serviceCollection;
}
Startup.cs of WebApp:
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.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
services.AddAuthorization();
services.AddControllersWithViews();
//services.AddRazorPages();
services.AddAuraServices(Configuration);
}
// 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("/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: "model-database", pattern: "{model-name:modeldatabasename}/{controller=ZipFiles}/{action=Index}/{id?}");
endpoints.MapControllerRoute(name: "default", pattern: "", new { controller = "Home", action = "Index" });
//endpoints.MapRazorPages();
});
}
}
But this time I am getting No service for Type Error. How can I solve this problem? Where do you think I am going wrong? Thanks
Edit:
As you can see BaseAddressAuthorizationMessageHandler is in namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication. It is supposed to be used with Blazor WebAssembly apps and it attaches the access token to the authentication header of HttpClient requests. BaseAddressAuthorizationMessageHandler depends on other services like IAccessTokenProvider which is responsible to return the access token. For example in web assembly IAccessTokenProvider default implementation retrieves the access token from browser session storage.
If you want to attach access tokens to your http requests your should probably implement your own DelegatingHandler instead of BaseAddressAuthorizationMessageHandler.
Old answer:
You have to register BaseAddressAuthorizationMessageHandler:
serviceCollection.AddTransient<BaseAddressAuthorizationMessageHandler>();

AuthenticateResult.Principal is null when trying to authenticate with Google

I'm trying to allow users to log in with their Google account on my ASP.NET Core Blazor app. Whenever I go to my app/login/google-login, everything works as expected. I get redirected to google's login page and I get to choose an account to log in with. After choosing my account, it takes a few seconds to load and then visual studio 2019 tells me this:
System.NullReferenceException: 'Object reference not set to an instance of an object.' Microsoft.AspNetCore.Authentication.AuthenticateResult.Principal.get returned null.
at this block of code:
var claims = response.Principal.Identities.FirstOrDefault().Claims.Select(claim => new
{
claim.Issuer,
claim.OriginalIssuer,
claim.Type,
claim.Value
});
Some debugging has revealed the following:
{"succeeded":false,"ticket":null,"principal":null,"properties":null,"failure":null,"none":true}
This is the response I get from Google's API formatted as JSON. Basically it tells me that the principal is null, which I could have guessed, but the rest is also null. What's going on here? Could this simply be an issue with my scopes on Google's end? I have reasons to believe this isn't the problem though since my app should be able to work with any API response without crashing, right?
Here's my LoginController.cs class:
[AllowAnonymous, Route("login")]
public class LoginController : Controller
{
[Route("google-login")]
public IActionResult GoogleLogin()
{
var properties = new AuthenticationProperties { RedirectUri = Url.Action("GoogleResponse") };
return Challenge(properties, GoogleDefaults.AuthenticationScheme);
}
[Route("google-response")]
public async Task<IActionResult> GoogleResponse()
{
var response = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var claims = response.Principal.Identities.FirstOrDefault().Claims.Select(claim => new
{
claim.Issuer,
claim.OriginalIssuer,
claim.Type,
claim.Value
});
return Json(claims);
}
}
Here's my Startup.cs:
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
//services.AddSingleton<WeatherForecastService>();
services.AddDbContext<Context>(options => options.UseSqlServer(Configuration.GetConnectionString("Context")));
services.AddIdentity<User, Role>().AddEntityFrameworkStores<Context>();
services.AddHttpContextAccessor();
services.AddScoped<IReservationService, ReservationService>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/login/google-login";
})
.AddGoogle(options =>
{
options.ClientId = Configuration["Google:ClientID"];
options.ClientSecret = Configuration["Google:ClientSecret"];
});
}
// 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("/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.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
If you need any additional info or code, I'll be happy to provide that ASAP.
This line, that is arguably a fairly big part of my project, was preventing communication with Google for who knows what reason.
services.AddIdentity<User, Role>().AddEntityFrameworkStores<Context>();
I now basically just went on without UserManager and RoleManager and just wrote manual methods for accessing AspNetUsers etc.
Probably not a real solution but it is what it is.

Swagger UI for net core 3.1 api is very slow

I updated Our net core API application from 2.1 to 3.1, SwashBuckle.Asp.NetCore to 5.0.0. Here is my startup set:
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)
{
string authServerUrl = "http://testserver.com/identityserver4";
services.AddControllersWithViews();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "NetCore API V1" });
// Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(authServerUrl + "connect/authorize"),
TokenUrl = new Uri(authServerUrl + "connect/token"),
Scopes = new Dictionary<string, string>
{
{ "netCoreAPI.read", "read permission" },
{ "netCoreAPI.write", "write permission" }
} }
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
},
new[] { "netCoreAPI.read", "netCoreAPI.write" }
}
});
});
}
// 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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("swagger/v1/swagger.json", "NetCore V1");
c.EnableDeepLinking();
c.OAuthClientId("clientId");
c.OAuthClientSecret("clientSecret");
c.OAuthAppName("netCoreApp");
c.OAuthScopeSeparator(" ");
c.OAuthUsePkce();
});
});
}
}
The initial Swagger UI displays relatively quickly. However, when a method in a controller is clicked, it takes 30 seconds to display "Try it out" button. Is there a way to debug the problem? Or Is there anyone having the same problem?
Before the code was converted from SwashBuckle 2.5 and net core 2.1 to SwashBuckle 5.0 and net core 3.1, the swagger UI works very fast.
I'm using "Swashbuckle.AspNetCore.SwaggerUI" Version="5.6.3" And with that version switching to "Swashbuckle.AspNetCore.Newtonsoft" was not really helping. There was no significant improvement.
Then I have fount this issue listed on Github. It is an old resolved issue but reopened in 2020. Where they explain Swagger UI 3.x has "Pretty print" and "Syntax highlight" which causing the render issues. It can be turned off in Swagger config:
SwaggerUI({
syntaxHighlight: {
activated: false,
theme: "agate"
},
//url: path,
....
});
In .NET Core you can access config as well: Setup.cs in Configure()
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Web API");
c.ConfigObject.AdditionalItems.Add("syntaxHighlight", false); //Turns off syntax highlight which causing performance issues...
c.ConfigObject.AdditionalItems.Add("theme", "agate"); //Reverts Swagger UI 2.x theme which is simpler not much performance benefit...
});
Are you using NewtonSoft?
You need to add:
Install-Package Swashbuckle.AspNetCore.Newtonsoft -Version 5.1.0
And add:
services.AddSwaggerGenNewtonsoftSupport();
// explicit opt-in - needs to be placed after AddSwaggerGen()
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft
Allowing the binary serialization in csproj speeded it up for me: <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
I faced a similar problem with swagger in my .Net 5 Web API project and it was fixed after following the steps and adding the code mentioned in both the above answers. To summarize:
Installed package Swashbuckle.AspNetCore.Newtonsoft 6.1.4
This line was already there in the Startup.cs:
services.AddSwaggerGenNewtonsoftSupport();
Added 2 lines of code in the Configure() of Startup.cs: (c.ConfigObject.AdditionalItems...)

Wire up MiniProfiler to ASP.NET Core Web API Swagger

I found only this manual describing how to make MiniProfiler work with ASP.NET Web API and Swagger UI, but I didn't find any manual describing how to make ASP.NET Core Web API work with MiniProfiler to show results in Swagger UI.
All you need is to customize Swagger index.html file just like it's explained in the documentation. After you created a custom HTML file add the following line into it:
<script async="async" id="mini-profiler" src="/profiler/includes.js?v=4.0.0.0" data-version="4.0.0.0" data-path="/profiler/" data-current-id="865f1487-f416-4d39-87fe-723e34847577" data-ids="" data-position="left" data-authorized="true" data-max-traces="15" data-toggle-shortcut="Alt+P" data-trivial-milliseconds="2.0" data-ignored-duplicate-execute-types="Open,OpenAsync,Close,CloseAsync"></script>
Basically the script above is the output of the MiniProfiler.Current.RenderIncludes() method.
Here is below the ConfigureServices and the Configure methods to see how both Swagger and Miniprofiler are configured
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
services.AddMiniProfiler(options =>
options.RouteBasePath = "/profiler"
);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMiniProfiler();
}
app.UseSwagger();
app.UseSwaggerUI(c => {
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("SOMpSwaggerNetCore.SwaggerIndex.html");
});
app.UseMvc();
}

.NET Core UseCors() does not add headers

This would be a duplicate of How does Access-Control-Allow-Origin header work?, but the method there also isn't working for me. I'm hoping I'm just missing something.
I am trying to get a Access-Control-Allow-Origin header in my response from my .NET Core Web API, which I am accessing via AJAX.
I have tried several things. All, unless noted otherwise, have been in the Startup.cs file.
Method 1
As per the Microsoft Documentation:
public void ConfigureServices(IServiceCollection services)
{
// Add database
services.AddDbContext<DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));
// Add the ability to use the API with JSON
services.AddCors();
// Add framework services.
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetService<DbContext>().Database.Migrate();
serviceScope.ServiceProvider.GetService<DbContext>().EnsureSeedData();
}
}
app.UseCors(builder => builder.WithOrigins("https://localhost:44306").AllowAnyMethod());
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"],
});
app.UseMvc();
}
Method 2
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddCors(options => options.AddPolicy("AllowWebApp",
builder => builder.AllowAnyMethod()
.AllowAnyMethod()
.AllowAnyOrigin()));
//.WithOrigins("https://localhost:44306")));
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
app.UseCors("AllowWebApp");
// ...
}
I've also tried adding [EnableCors("AllowWebApp")] on both the Controller and Method.
From Postman, I get:
content-encoding → gzip
content-type → text/plain; charset=utf-8
date → Wed, 25 Jan 2017 04:51:48 GMT
server →Kestrel
status → 200
vary → Accept-Encoding
x-powered-by → ASP.NET
x-sourcefiles → =?UTF-8?B?[REDACTED]
I've also tried it in Chrome, and gotten similar headers.
If it matters, the method I'm trying to access has an Authorize attribute on it. But that part should be working fine (I'm at least getting a good response)
So, am I missing something very obvious, or did this get broken? I'm currently running version 1.1.0.
Edit adding JS and Controller Stub
function getContactPreviews(resultsCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
if (xmlhttp.readyState == XMLHttpRequest.DONE && xmlhttp.status == 200) {
resultsCallback(JSON.parse(xmlhttp.response));
}
}
xmlhttp.open("GET", "https://localhost:44357/api/User/ContactsPreview", true);
xmlhttp.setRequestHeader("Authorization", "Bearer " + localStorage.getItem("AuthorizationToken"));
xmlhttp.send();
}
Controller Stub
[Authorize]
[Route("api/[controller]")]
public class UserController : ApiController
{
[HttpGet(nameof(ContactsPreview))]
[EnableCors("AllowWebApp")]
public IEnumerable<Customer> ContactsPreview()
{
// ...
}
}
The problem is that when using Bearer authentication (or any I would imagine), it adds a header "Authorization", and the server will only give an okay if the setup allows for that header.
There's two ways to solve the problem, and below is the only code needed. It goes in the Configure() method in Startup.cs in the Web API solution.
Method 1: Allow all headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.AllowAnyHeader());
Method 2: Allow specific headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.WithHeaders("authorization", "accept", "content-type", "origin"));
The extra headers are because, per the documentation:
Browsers are not entirely consistent in how they set Access-Control-Request-Headers. If you set headers to anything other than "*", you should include at least "accept", "content-type", and "origin", plus any custom headers that you want to support.
The Access-Control-Allow-Origin header is returned only if:
The request includes an "Origin" header.
The requested origin matches the CORS policy.
Then the server returns the ACAO-header with the origin URL as value.
The Origin header is usually set by the XMLHttpRequest object.
For more information, see How CORS works
In Startup.cs file, add following
public CorsPolicy GenerateCorsPolicy(){
var corsBuilder = new CorsPolicyBuilder();
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url. Don't add a forward slash on the end!
corsBuilder.AllowCredentials();
return corsBuilder.Build();
}
In ConfigureServices method:
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins", GenerateCorsPolicy());
});
// To Apply CORS globally throughout the application
// In Configure method, add
app.UseCors("AllowAllOrigins");
[DisableCors]
Using DisableCors attribute, we can disable CORS for a controller or an action.
//To Enable CORS controller basis - If you apply globally you don't need this one.
[EnableCors("AllowAllOrigins")]
public class HomeController: Controller {}
In Startup.cs at the end of ConfigureServices() add this:
services.AddCors();
Then in Configure() at the top add this:
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("*"));
// alternatively you could use .With... methods to specify your restrictions:
// app.UseCors(x => x.WithOrigins("http://domain1.com").WithMethods("GET","POST").WithHeaders("Authorization").WithExposedHeaders("*"));
As of date 03/17/2019, .NET Core version 2.1:
This will possibly save some time to other poor souls...at some point I started to be frustrated and almost gave up on .NET Core WebApi as a separate project.
In real life circumstances, there are other configurations in Startup functions e.g. I had Swagger, DI registrations etc. I wasn't able to make bloody thing work until I put both AddCors() and UseCors() methods to be the first one getting called in configuration functions.
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("SomePolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("SomePolicy");
After that, calls from Angular 6 app (Swagger Typescript client calls) started to work as a charm.
I wasted hours on this problem today, only to discover it's because .Net Core 3 doesn't support preflight OPTIONS requests if you use the Endpoint routing RequirePolicy method of enabling CORS!
The official documentation does mention this, but it wasn't called out in an obvious warning block so I'd totally missed it.
The following will fix the problem, but it'll apply a global CORS policy, so caveat emptor!
Service Configuration:
public void ConfigureServices(IServiceCollection services)
{
string[] corsOrigins = Configuration.GetSection("AllowedHosts").Get<string[]>();
services.AddCors(options =>
{
options.AddPolicy("AllowConfiguredOrigins", builder => builder
.WithOrigins(corsOrigins)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
});
...
Basically, don't do this:
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("AllowConfiguredOrigins");
});
...
...do this instead
Configure()
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors("AllowConfiguredOrigins");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
...
I want to add one more possibility for those who may have followed the advice above and it is still not working. In my case I was not getting the header returned (or only getting it on the first request) because of the order of registration in the pipeline.
I changed the order from this:
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseCors("WideOpen");
app.UseMvc();
To this:
app.UseCors("WideOpen");
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseMvc();
That resolved my issue.

Categories