ASP.NET Core - Swashbuckle not creating swagger.json file - c#

I am having trouble getting the Swashbuckle.AspNetCore (1.0.0) package to generate any output. I read the swagger.json file should be written to '~/swagger/docs/v1'. However, I am not getting any output.
I started with a brand new ASP.NET Core API project. I should mention this is ASP.NET Core 2. The API works, and I am able to retrieve values from the values controller just fine.
My startup class has the configuration exactly as described in this article (Swashbuckle.AspNetCore on GitHub).
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.AddMvc();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
}
// 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();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyAPI V1");
});
}
else
{
app.UseExceptionHandler();
}
app.UseStatusCodePages();
app.UseMvc();
//throw new Exception();
}
}
You can see the NuGet references...
Again, this is all the default template, but I include the ValuesController for reference...
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}

I had the same problem. Check http://localhost:XXXX/swagger/v1/swagger.json. If you get any a errors, fix them.
For example, I had an ambiguous route in a base controller class and I got the error: "Ambiguous HTTP method for action. Actions require an explicit HttpMethod binding for Swagger 2.0.".
If you use base controllers make sure your public methods use the HttpGet/HttpPost/HttpPut/HttpDelete OR Route attributes to avoid ambiguous routes.
Then, also, I had defined both HttpGet("route") AND Route("route") attributes in the same method, which was the last issue for swagger.

I believe you missed these two lines on your Configure:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("v1/swagger.json", "MyAPI V1");
});
}
To access Swagger UI, the URL should be: http://localhost:XXXX/swagger/
The json can be found at the top of Swagger UI:

If your application is hosted on IIS/IIS Express try the following:
c.SwaggerEndpoint("../swagger/v1/swagger.json", "MyAPI V1");

I was running into a similar, but not exactly the same issue with swagger. Hopefully this helps someone else.
I was using a custom document title and was not changing the folder path in the SwaggerEndPoint to match the document title. If you leave the endpoint pointing to swagger/v1/swagger.json it won't find the json file in the swagger UI.
Example:
services.AddSwaggerGen(swagger =>
{
swagger.SwaggerDoc("AppAdministration", new Info { Title = "App Administration API", Version = "v1.0" });
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/AppAdministration/swagger.json", "App Administration");
});

#if DEBUG
// For Debug in Kestrel
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Web API V1");
#else
// To deploy on IIS
c.SwaggerEndpoint("/webapi/swagger/v1/swagger.json", "Web API V1");
#endif
When deployed to IIS webapi(base URL) is the Application Alias. You need to keep Application Alias(base URL) same for all IIS deployments because swagger looks for swagger.json at "/swagger/v1/swagger.json" location but wont prefix application Alias(base URL) that is the reason it wont work.
For Example:
localhost/swagger/v1/swagger.json - Couldn't find swagger.json

You must conform to 2 rules:
Decorate all actions with explicit Http Verbs like[HttpGet("xxx")], [HttpPost("xxx")], ... instead of [Route("xxx")].
Decorate public methods in controllers with [NonAction] Attribute.
Note that http://localhost:XXXX/swagger/ page requests for http://localhost:XXXX/swagger/v1/swagger.json file, but an Exception will occur from Swagger if you wouldn't conform above rules.

After watching the answers and checking the recommendations, I end up having no clue what was going wrong.
I literally tried everything. So if you end up in the same situation, understand that the issue might be something else, completely irrelevant from swagger.
In my case was a OData exception.
Here's the procedure:
1) Navigate to the localhost:xxxx/swagger
2) Open Developer tools
3) Click on the error shown in the console and you will see the inner exception that is causing the issue.

I am moving my comment to an answer since it appears to be helpful.
To avoid issues with IIS aliases, remove /swagger/ from the URL path. It should look like this:
app.UseSwaggerUI(c => { c.SwaggerEndpoint("v1/swagger.json", "API name"); });

I don't know if this is useful for someone, but in my case the problem was that the name had different casing.
V1 in the service configuration - V capital letter
v1 in Settings -- v lower case
The only thing I did was to use the same casing and it worked.

If you have any issues in your controller to map to an unique URL you get this error.
The best way to find the cause of issue is exclude all controllers from project. Then try running the app by enabling one controller or one or more methods in a controller at a time to find the controllers/ controller method(S) which have an issue. Or you could get smart and do a binary search logic to find the disable enable multiple controller/methods to find the faulty ones.
Some of the causes is
Having public methods in controller without HTTP method attributes
Having multiple methods with same Http attributes which could map to same api call if you are not using "[action]" based mapping
If you are using versioning make sure you have the method in all the controller versions (if using inheritance even though you use from base)

A common error that we make when use Swagger is to give the same name to(NET ASP) two or more routes. this cause that swagger cannot generate the JSON file. for example, this is a wrong way
[HttpPost, Route("Start")]
public async Task<TransactionResult> WipStart(BodyWipStartDTO data)
{
return await _wipServices.WipStart(data);
}
Other action with the same route name but different action name
[HttpPost, Route("Start")]
public async Task<TransactionResult> WipAbort(BodyWipStartDTO data)
{
return await _wipServices.WipAbort(data);
}
This a correct way
[HttpPost, Route("Start")]
public async Task<TransactionResult> WipStart(BodyWipStartDTO data)
{
return await _wipServices.WipStart(data);
}
[HttpPost, Route("Abort")]
public async Task<TransactionResult> WipAbort(BodyWipStartDTO data)
{
return await _wipServices.WipAbort(data);
}

You actually just need to fix the swagger url by removing the starting backslash just like this :
c.SwaggerEndpoint("swagger/v1/swagger.json", "MyAPI V1");
instead of :
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyAPI V1");

Be aware that in Visual Studio 2022 and .NetCore 6 if you create a new ASP.NET Core Web App, Program.cs has the oposite check for Development environment.
instead of
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
you will find
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
// You shoukd add swagger calls here
app.UseSwagger();
app.UseSwaggerUI();
If you create a new project by selecting the template ASP.NET Core Web API and check "Enable OpenAPI support" you will have different Program.cs with preinstalled swagger package and related code.
This took some time for me to find, hope to help someone.

Adding a relative path worked for me:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("../swagger/v1/swagger.json", "My App");
});

Personally I had the same issue and when I tried again today after a while I found in the new version (2.5.0) that going in the json I could see an explanation of the error that was in here.
Also another thing that helped to fix it to me was removing the hosting information connected to the website that is hold inside "..vs\config\applicationhost.config" at the root of the solution folder
I removed the element that was configuring the website.
<site name="**" id="9">
<application path="/" applicationPool=""></application>
<bindings></bindings>
</site>

I had this problem when I used a inner class in Post parameters
[HttpPost]
public async Task Post([FromBody] Foo value)
{
}
Where Foo is
public class Foo
{
public IEnumerable<Bar> Bars {get;set;}
public class Bar
{
}
}

Try to follow these steps, easy and clean.
Check your console are you getting any error like "Ambiguous HTTP method for action. Actions require an explicit HttpMethod binding for Swagger 2.0."
If YES:
Reason for this error: Swagger expects
each endpoint should have the method (get/post/put/delete)
.
Solution:
Revisit your each and every controller and make sure you have added
expected method.
(or you can just see in console error which controller causing ambiguity)
If NO. Please let us know your issue and solution if you have found any.

Same problem - easy fix for me.
To find the underlying problem I navigated to the actual swagger.json file which gave me the real error
/swagger/v1/swagger.json
The actual error displayed from this Url was
NotSupportedException: Ambiguous HTTP method for action ... Actions require an explicit HttpMethod binding for Swagger/OpenAPI 3.0
The point being
Actions require an explicit HttpMethod
I then decorated my controller methods with [HttpGet]
[Route("GetFlatRows")]
[HttpGet]
public IActionResult GetFlatRows()
{
Problem solved

Make sure you have all the required dependencies, go to the url xxx/swagger/v1/swagger.json you might find that you're missing one or more dependencies.

I was getting this Swagger error when I created Version 2 of my api using version headers instead of url versioning. The workaround was to add [Obsolete] attributes to the Version 1 methods then use SwaggerGeneratorOptions to ignore the obsolete api methods in Startup -> ConfigureServices method.
services.AddSwaggerGen(c =>
{
c.SwaggerGeneratorOptions.IgnoreObsoleteActions = true;
c.SwaggerDoc("v2", new Info { Title = "My API", Version = "v2" });
});

I had the same problem. I was using swagger like below mentioned pattern i.e. "../swagger/v1/swagger.json" because I am using IIS Express.Later than I change it to
"/swagger/v1/swagger.json"and clean,rebuild the solution worked for me.

You might forgetting to include.. StartUp.cs/Configure()
app.UseSwagger();
Check if you forgot to include, you error must be remove.

I'd a similar issue, my Swagger documentation broke after I was adding async version of APIs to existing ones.
I played around the Swagger DLL's by installing / Reinstalling, finally commenting newly added APIs, and it worked.
Then I added different signature in attributes, and bingo!, It worked.
In your case, you are having two API with matching signatures
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{`enter code here`
return "value";
}
Try providing different names in attributes like
[HttpGet("List")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("ListById/{id}")]
public string Get(int id)
{
return "value";
}
This should solve the issue.

I have came across the same issue, and noticed that my API has not hosted in the root folder and in an virtual directory.
I moved my API to the root folder in IIS and worked.
More info in this answer

Take a look on Chrome developer tools, sometimes, swagger.json request throws http 500, witch means that there is some inconsistency on your controllers.
For example: In my case, there is an "Ambiguous HTTP method for action":

Also I had an issue because I was versioning the application in IIS level like below:
If doing this then the configuration at the Configure method should append the version number like below:
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/1.0/swagger/V1/swagger.json", "Static Data Service");
});

I was able to fix and understand my issue when I tried to go to the swagger.json URL location:
https://localhost:XXXXX/swagger/v1/swagger.json
The page will show the error and reason why it is not found.
In my case, I saw that there was a misconfigured XML definition of one of my methods based on the error it returned:
NotSupportedException: HTTP method "GET" & path "api/Values/{id}" overloaded by actions - ...
...
...

In my case problem was in method type, should be HttpPOST but there was HttpGET
Once I changed that, everything starts work.
https://c2n.me/44p7lRd.png

You should install the following packages into your project.
5.0.0-rc4 version of Swashbuckle is the minimum. Otherwise, it won't work.
As of now, directly installing it from Nuget, installs the old versions which won't work for Core 3.
I inserted the following lines into .csproj project file like that:
<PackageReference Include="Microsoft.OpenApi" Version="1.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="5.0.0-rc4" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0-rc4" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="5.0.0-rc4" />
After that, Rebuild installs the newer versions.
If not, you can use restore too.
In the Startup.cs, you should configure Swashbuckle like that:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
services.AddMvc();
}
 
// 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();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
//c.RoutePrefix = String.Empty;
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Just go to the "https://localhost:5001/swagger/index.html" and you'll see the Swagger UI.
(5001 is my local port, you should change it with yours)
It took a little time for me to figure it out.
I hope it will help others :)

Answer:
If using directories or application with IIS or a reverse proxy,<br/> set the Swagger endpoint to a relative path using the ./ prefix. For example,<br/> ./swagger/v1/swagger.json. Using /swagger/v1/swagger.json instructs the app to<br/>look for the JSON file at the true root of the URL (plus the route prefix, if used). For example, use http://localhost:<br/><br/><port>/<route_prefix>/swagger/v1/swagger.json instead of http://localhost:<br/><port>/<virtual_directory>/<route_prefix>/swagger/v1/swagger.json.<br/>
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
//c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyAPI V1");
//Add dot in front of swagger path so that it takes relative path in server
c.SwaggerEndpoint("./swagger/v1/swagger.json", "MyAPI V1");
});
}
[Detail description of the swagger integration to web api core 3.0][1]
[1]: https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=visual-studio

Related

.net 6 api Redirect page cannot be found

I'm creating and testing my first api, using visual studio .net 6 core and EF core. Right now I'm just trying to make sure I have everything functioning. I have a single controller, and I want to redirect to an html page that gives general API usage info. When I run the debugger and the browser opens to https://localhost:xxxx I append /api/values to the end and this gets handled by my controller:
public class ValuesController : ControllerBase
{
private readonly IWebHostEnvironment _env;
public ValuesController(IWebHostEnvironment env)
{
_env = env;
}
// GET: api/<ValuesController>
[HttpGet]
public ActionResult Get() //was return type IEnumerable<string>
{
//return new string[] { _env.ContentRootPath, _env.WebRootPath }; //<- WebRootPath returns as null
return Redirect("../Index.html");
}
//other stuff removed for brevity, just calling the above get function
}
In my code base directory I have the Index.html file created, and set to copy with a publish. But I can't get the redirect to this page to work.
The error I get is:
No webpage was found for the web address: https://localhost:xxxx/api/Index.html
HTTP ERROR 404
When I open Index.html from the file browser it renders properly in Chrome.
I have tried using Index.html, /Index.html, and ../Index.html in the redirect call all with the same error, though from different locations.
When I ran with the string array return I see that my ContentRootPath is the path to my project root (where Index.html exists), and that WebRootPath = null.
In launchSettings.json the applicationURL is listed a couple of times. The first is in iiSettings and given as http://localhost:xxxxx (does not seem to be used) and the second in profiles and given as https://localhost:xxxx;http://localhost:yyyy (I use the https port and getting the redirect in the controller to work, because the address bar shows localhost:xxxx/api/Index.html but the page is the error text above.
I have created a folder api in the project and put a copy of Index.html in there, still with the same error.
Here is my Program.cs app initialization:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ApiDbContext>();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddControllers();
builder.Services.AddHealthChecks();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.MapControllers();
app.Run();
How do I serve up a static page from my api?
Ok, for some reason my googling got better after I posted this question. If anyone is looking here for a similar problem, I found the solution here.
Simply return a ContentResult object:
return new ContentResult
{
Content = System.IO.File.ReadAllText(#"./Index.html"),
ContentType = "text/html"
}; //new string[] { "value1", "value2" };
ControllerBase has a Content() method that will do this for you as well, but what I have above is working within my public ActionResult Get() method.
RedirectToAction("Directory");
You can try doing this, it will throw you directly to the Index page

Unable to setup a controller on Blazor Server

I am trying to add an MVC, or WebAPI, or whatever controller to my Blazor Server project.
I have read numerous SO questions, blogs and etc. on the matter, like this. None of them work.
No matter what I add to my "endpoints" or "app" in my "Configure" or "ConfigureServices" methods when I start my application in debug and try to make a request using Postman it times out.
I tried:
Adding controller exactly as shown in the linked answer.
Adding any and all of those in my Startup:
endpoints.MapControllers()
endpoints.MapGet("/aaa", async context => await context.Response.WriteAsync("Hello World!"););
endpoints.MapDefaultControllerRoute()
app.UseMvc()
app.UseMvcWithDefaultRoute()
Neither does Postman get any answer (times out) nor does a breakpoint I've set in the "Get" method of the controller get triggered.
What can I do to get a controller working?
I did the following (which "worked on my machine"):
create a new BlazorApp:
dotnet new blazorserver -o BlazorApp --no-https
add a controller:
namespace BlazorApp.Controllers
{
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class TestController : ControllerBase
{
[HttpGet("test")]
public ActionResult<string> Test()
{
return "TODO";
}
}
}
add endpoints.MapControllers(); to Satrtup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers(); // new
endpoints.MapBlazorHub(); // existing
endpoints.MapFallbackToPage("/_Host"); // existing
});
run the app
go to http://localhost:5000/test (you'll get the "TODO" response)
go to http://localhost:5000 (you'll see the Blazor page)
EDIT
#Tessaract in the comments mentioned that the site was running on HTTPS while the plain HTTP was being queried (and therefor didn't work).
I know is too late, but meaby helpfull somenone in future.
Check add Controllers in Program.cs like this
builder.Services.AddControllers();
When builder is
var builder = WebApplication.CreateBuilder(args);
And dont forget about this:
var app = builder.Build();
app.MapControllers();
app.Run();

How do I change the Swagger default URL and use a custom one?

I have an API that I created in .NetCore 3.1 and have enabled Swagger(OAS3) using Swashbuckle. By default when my app starts if brings up the Swagger page using this URL:
http://{port}/swagger.index.html
I would like to customize the Swagger URL so that it includes the name of the application that is running. The reason I am doing this is because I am using path-based routing with Nginx running in AWS Fargate.
I will have several API containers running in the Fargate task and Nginx will receive the REST requests coming from the Application Load Balancer and from the path (e.g. /api/app1), it will route the request to the correct container port for the target application.
So, for example, I have three apps: App1 on port 5000, App2 on Port 5001 and App3 on port 5003.
If the user makes a request to https://api/app1, Nginx will detect the path and forward the request to port 5000, which is App1's container port.
However, to make sure that the correct Swagger page comes up, I need to add "api/App1" to Swagger's URL so that Nginx will forward the request to the correct container. In this case, it's App1.
In other words, I want my Swagger URL to look like this:
https://api/app1/swagger/index.html
What I've tried
In my Startup.cs file I have added the following:
// Define prefix for application
private readonly string baseApplicationRoute = "api/app1";
// Enable OAS3 JSON middleware
app.UseSwagger(c =>
{
c.RouteTemplate = baseApplicationRoute+"/{documentName}/swagger.json";
});
app.UseSwaggerUI(c =>
{
var endpoint = $"/{baseApplicationRoute}/{version.ToLower()}/swagger.json";
c.SwaggerEndpoint(endpoint, $"APP1 API - {version}");
c.RoutePrefix = string.Empty;
});
This compiles and works, however it is still using the same Swagger URL of:
http://{port}swagger.index.html
I think all this is doing is changing the location of the swagger.json because on the Swagger UI that comes up it is showing:
/api/app1/v1/swagger.json
My launchSettings.json file is specifying the "launchUrl" as "swagger".
I think I'm close, but I am obviously missing something. To recap I'm just trying to change:
The default Swagger URL
http://{port}swagger.index.html
To my custom one here:
http://{port}/api/app1/v1/swagger.index.html
That way Nginx can detect "/api/app1" and route to the correct container.
What am i missing?
I found the solution to this issue:
In the Configure section of Startup.cs I did the following:
First I added the folowing variable:
private readonly string swaggerBasePath = "api/app";
Next I configured the path using UseSwagger and UseSwaggerUI to use the swaggerBasePath variable:
app.UseSwagger(c =>
{
c.RouteTemplate = swaggerBasePath+"/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"/{swaggerBasePath}/swagger/v1/swagger.json", $"APP API - {version}");
c.RoutePrefix = $"{swaggerBasePath}/swagger";
});
Finally, I modified launchSettings.json to point to the new base path:
"launchUrl": "api/app/swagger",
Then is was able to hit the Swagger page using:
https://localhost/api/app/swagger/index.html
I testing this with Nginx and it was able to route to the correct container.
I can easily tweak the base path (for instance to add the API version number) by simply modifying the swaggerBasePath variable and tweaking the launchSettings.json file to match the value of the variable.
Hopefully, this will help someone in the future.
(I am using .Net 6)
I needed this because I was facing issue in api gateway. So, What I did, I left my launch settings as it is.
launchsettings
"launchUrl": "studentservice/api/swagger",
I made these two changes in my Startup.cs file.
Note: Your launchsettings url and routeprefix url should match.
In ConfigureService Method, I have added SwaggerDoc
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("student", new OpenApiInfo { Title = "Student Service Api", Version = "1.0" });
}
In Configure Method, I have added SwaggerDoc
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.)
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/student/swagger.json", "Student Services Api");
c.RoutePrefix = "studentservice/api/swagger";
});
}

How to map fallback in ASP .NET Core Web API so that Blazor WASM app only intercepts requests that are not to the API

I have a Blazor WebAssembly solution with a client project, server project and shared project, based on the default solution template from Microsoft. I'm editing and debugging in Visual Studio 2019 preview with Google Chrome.
Out-of-the-box, the solution has a single start-up project, which is the server application. That server application has a project reference to the client application. You can set it to use HTTPS by checking "Enable SSL" in the server project properties and I have done that.
When you click on debug it works perfectly.
Now I want to change it so that the Blazor WASM app only responds to requests from https://localhost:44331 and not requests to https://localhost:44331/api. These requests should be dealt with by API Controller endpoints of the server application instead. So, if somebody visits https://localhost:44331/api/something, and no such API endpoint exists, they should receive a 404 error code from the API and not be routed to the usual Blazor page saying "Sorry, there's nothing at this address."
I want to use this extra "/api" portion of the URL to keep the requests to the API separate from requests for pages. I think this will be closer to how a normal setup would be in production. I hope it's clear what I'm trying to do.
Here is a sample Controller declaration with route attribute:
namespace BlazorApp2.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
// Etc.
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
//etc.
}
///etc.
}
}
Here is what I have tried in my Startup.cs and it does not work. Can anybody suggest something that will please?
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Etc.
app.UseStatusCodePages();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
// The line commented out below is the out-of-the-box behaviour for a Blazor WASM app with ASP NET Core API. This is the line I want to replace.
// endpoints.MapFallbackToFile("index.html");
// The line below is my (failed) attempt to get the behaviour I want.
endpoints.MapFallback(HandleFallback);
});
}
private async Task HandleFallback(HttpContext context)
{
var apiPathSegment = new PathString("/api"); // Find out from the request URL if this is a request to the API or just a web page on the Blazor WASM app.
bool isApiRequest = context.Request.Path.StartsWithSegments(apiPathSegment);
if (!isApiRequest)
{
context.Response.Redirect("index.html"); // This is a request for a web page so just do the normal out-of-the-box behaviour.
}
else
{
context.Response.StatusCode = StatusCodes.Status404NotFound; // This request had nothing to do with the Blazor app. This is just an API call that went wrong.
}
}
Does anybody know how to get this working how I'd like, please?
To recap the problem, when somebody makes a request to:
https://yourapp.com/api/someendpoint
and /api/someendpoint can't be found, they're taken to a Blazor page. This default behaviour is weird. For requests starting with /api, they were expecting an HTTP Status Code and probably a JSON object too, but instead, they got HTML. Maybe they don't even use your app. Maybe they're not even human (more likely they're a piece of software).
This is how you send them an HTTP Status Code instead.
On your controllers:
[Route("api/[controller]")]
public class SampleController : ControllerBase
{
// ...
}
In Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.Map("api/{**slug}", HandleApiFallback);
endpoints.MapFallbackToFile("{**slug}", "index.html");
});
}
private Task HandleApiFallback(HttpContext context)
{
context.Response.StatusCode = StatusCodes.Status404NotFound;
return Task.CompletedTask;
}
Pretty sure this should work:
endpoints.MapFallbackToFile("{*path:regex(^(?!api).*$)}", "index.html"); // don't match paths beginning with api
I think it means something like only match URLs where the path does not start with api.
You can fix this by explicitly mapping Blazor fallback only for paths that don't start with /api and, then only mapping api paths for those that do start with /api, like I mention in this answer to my owner question. This gives the benefit that instead of just returning a 404 if you try to POST to a GET api method, you will get the proper api response of 405, or whatever other error the api would normally return given the request.
//explicitly only use blazor when the path doesn't start with api
app.MapWhen(ctx => !ctx.Request.Path.StartsWithSegments("/api"), blazor =>
{
blazor.UseBlazorFrameworkFiles();
blazor.UseStaticFiles();
blazor.UseRouting();
blazor.UseEndpoints(endpoints =>
{
endpoints.MapFallbackToFile("index.html");
});
});
//explicitly map api endpoints only when path starts with api
app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"), api =>
{
//if you are not using a blazor app, you can move these files out of this closure
api.UseStaticFiles();
api.UseRouting();
api.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
Using code from #Darragh I get the following error:
endpoints.MapFallbackToPage("{path:regex(^(?!api).$)}", "index.html");
System.ArgumentException: ''index.html' is not a valid page name. A
page name is path relative to the Razor Pages root directory that
starts with a leading forward slash ('/') and does not contain the
file extension e.g "/Users/Edit". (Parameter 'pageName')'
The code will run if I use MapFallbackToFile instead of MapFallbackToPage like the original code.
However when I tested the regex it matched everything including an API URL:
https://regex101.com/r/nq7FCi/1
My Regex would look like this instead: ^(?!.*?(?:\/api\/)).*$ based on this answer:
https://stackoverflow.com/a/23207219/3850405
https://regex101.com/r/qmftyc/1
When testing this out It did not work anyway and urls containing /api/ was redirected to index.html.
My final code is based on #benjamin answer but with the original MapFallbackToFile used last.
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.Map("api/{**slug}", HandleApiFallback);
endpoints.MapFallbackToFile("index.html");
});
private Task HandleApiFallback(HttpContext context)
{
context.Response.StatusCode = StatusCodes.Status404NotFound;
return Task.CompletedTask;
}
I have tried this with Blazor WebAssembly .NET 5. After publishing to IIS, the previously suggested solutions do not work.
The answer to this question is provided here. Tested and working.
Shortly:
Edit wwwroot\service-worker.published.js file and add the path to exclude, in this case /api/.
const shouldServeIndexHtml = event.request.mode === 'navigate' &&
!event.request.url.includes('/api/')
If you start from a Blazor WASM hosted solution, you'll a get a sample, just launch
dotnet new blazorwasm --hosted
It create a solution with 3 projects :
|-- Client
|-- Server
|-- Shared
In The Server Startup class, the middleware pipeline is setup like this :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
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.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
The controller define its route with Route attribute. If you want to host the controller at /api/{controller} use the Route attribute value api/[controller]:
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
With all other solutions applied, I still encounter the problem in ASP.NET Core 7 (not sure if the version matters) and it only happens on Production server. Turned out there's this difference between dev and production environment:
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error"); // <-- This line
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
Removing app.UseExceptionHandler and I can see exceptions again.

Swagger not loading - Failed to load API definition: Fetch error undefined

Trying to setup swagger in conjunction with a web application hosted on IIS express. API is built using ASP Net Core. I have followed the instructions prescribed on the relevant microsoft help page regarding Swashbuckle and ASP.NET Core.
Thus far I have got the swagger page to load up and can see that the SwaggerDoc that I have defined is loading, however no API's are present. Currently am getting the following error:
"Fetch error undefined ./swagger/v1/swagger.json"
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// services.AddDbContext<TodoContext>(opt =>
// opt.UseInMemoryDatabase("TodoList"));
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "API WSVAP (WebSmartView)", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("./swagger/v1/swagger.json", "My API V1");
c.RoutePrefix = string.Empty;
});
app.UseMvc();
}
}
So after a lot of troubleshooting it came down to basically two things, but I feel that in general this could be helpful to someone else in the future so I'm posting an answer.
First- if ever your stuck with the aforementioned error the best way to actually see whats going on is by adding the following line to your Configure() method
app.UseDeveloperExceptionPage();
Now if you navigate to the 'swagger/v1/swagger.json' page you should see some more information which will point you in useful direction.
Second- now for me the error was something along the lines of
'Multiple operations with path 'some_path' and method 'GET' '
However these API were located inside of dependency libraries so I was unable to apply a solution at the point of definition. As a workaround I found that adding the following line to your ConfigureServices() method resolved the issue
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "API WSVAP (WebSmartView)", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); //This line
});
Finally- After all that I was able to generate a JSON file but still I wasn't able to pull up the UI. In order to get this working I had to alter the end point in Configure()
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("./v1/swagger.json", "My API V1"); //originally "./swagger/v1/swagger.json"
});
I'm not sure why this was necessary, although it may be worth noting the web application's virtual directory is hosted on IIS which might be having an effect.
NOTE: Navigating to swagger/v1/swagger.json will give you more details, for me it was causing issue due to undecorated action. This information is mentioned in comment by #MarkD
I've been working with .Net Core 3.1 and I spent some time to find out and understanding what was going on.
The issue can arise from many different reasons:
Swagger configuration errors
Classes with the same name but in different namespaces
Public methods without the rest attribute (Get, Post, etc.)
First, take a look the link below just to check if your setup is ok:
Add Swagger(OpenAPI) API Documentation in ASP.NET Core 3.1
Then,
A good tip to find out the problem is to run the application without to use IISExpress and check the console log. Any error found to generate the documentation will be displayed there.
In my case, the problems was that I had a public method (that should be private) without any rest attribute:
After change the method from public to private I solve the issue.
I was able to find the error by opening the network tab and looking at the response for swagger.json
Simply navigate to https://localhost:{PortNo}/swagger/v1/swagger.json and get much more details about the error message.
also I had similar problem in .NET 5.0, I solved below way:
I added this line as attribute over controller:
[Consumes("application/json")]
I've been working with .NET 5 and I spent some time trying to understand what was going on.
I got an error like the one below:
Then I resolved this problem by the following:
Open startup.cs file
Add the following code in Configure method
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger(c =>
{
c.RouteTemplate = "/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"));
}
And in ConfigureServices method
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
Thanks to TheCodeBuzz for Resolved: Failed to load API definition (undefined /swagger/v1/swagger.json)
Note the difference between the RouteTemplate string and the SwaggerEndpoint string. One uses {documentName} and the other uses "v1" as a literal.
I've come across the same error before, after struggling to find the reason, I discovered that one of my API in one of my controllers have no HTTP verb as an attribute, So I fixed it by putting [HttpGet] on my API.
So here is my advice, check your API controllers, maybe you forget the same thing as me!
Take a look at my code, I realized that I should change this :
public async Task<Product> ProductDetail(int id)
{
return await _productQueries.GetProductDetail(id);
}
to this:
[Route("ProductDetail")]
[HttpPost]
public async Task<Product> ProductDetail(int id)
{
return await _productQueries.GetProductDetail(id);
}
I had similar issue, I solved it using the Route attribute on the offending controller method:
[HttpGet, Route("Throw")]
public ActionResult<string> Throw()
{
_logger.LogInformation("I think I am going to throw up");
throw new NotSupportedException("For testing unhandled exception logging.");
}
I felt that ResolveConflictingActions may potentially sweep a real issue under the rug.
I had two issues that caused the same error.
I have two classes with the same name under two different namespaces. Swagger could not reconcile this when generating the swagger doc. To fix it I added the line options.CustomSchemaIds(x => x.FullName);
See explanation here
I had a method without an [HttpGet] annotation. Swagger needs the HTTP endpoints to be explicitly defined.
I found both issues by inspecting the Output in visual studio after the API loaded.
I just spent two hours on this issue, but my cause was entirely different, it had NOTHING to do with routes or annotations. I had 2 classes with the same name (but different namespaces): MyProject.Common.ClassName and MyProject.Api.ClassName. Swagger/swashbuckle couldn't tell the difference between the two, so I got that useless error.
Those 2 hours were spent trial-and-error commenting out controllers and endpoints, to finally find 3 endpoints offending endpoints. All 3 endpoints had different routes, different (or no) custom authorization, and different method names. It turned out that all 3 endpoints either accepted a parameter, or returned an object, that contained the API version of my class. Nowhere was the Common version used. Swagger couldn't tell them apart, and puked all over itself.
Why oh why can't Swagger or Swashbuckle provide actual error messages? Would have saved me a couple of hours...
I just forgot to add HTTP attributes in my controller as soon as I add HTTP attribute it works like a charm for me.
Source : https://www.benday.com/2020/12/16/webapi-core-swagger-failed-to-load-api-definition-error/
Here we go:
I created WEB Controller instead of WEB API Controller. That makes this kind of error.
During creation of new Controller, make sure that you created right WEB API controller.
Surely it is one of the Controller's method that is faulty. To get the method, at times you might need to take out all your controllers, Try and insert them one after the other then you will test along to find the Controller with bugs.
For ex. If you have like 3Controllers say
>Controller
>>>AuthController
>>>UserController
>>>HomeController
Take two out of the controllers out and test the controller by adding one controller after each successful testing. With that you will know the controller that has a faulty method.
>Controller
>>>AuthController
If the methods in AuthenController is fine, It will run, If not Check the methods.
>Controller
>>>AuthController
>>>UserController
and carry out the next check on the controller like that of Authen.
I had the same problem, so I checked it using inspect element on the browser. The "Console" tab shows the file where the problem originated from (v1/swagger/json:1). Opening it by clicking it showed that one of the helper methods I used in my controller was "Public". Changing it to "Private" fixed the problem for me.
This page also has good tips:
https://btrehberi.com/swagger-failed-to-load-api-definition-fetch-error-undefined-hatasi-cozumu/yazilim/
Swagger in my case needed [HttpAction] with all public members in controller. Unfortunately I misspelled constructor name and since it was public, was throwing this error.
For ASP.NET Core 3.1 I had to ensure the verb were not ambiguous and I found this out by first running the API project without IIS in VS2019 (Green Arrow > left-click the carrot icon and select the name of the project this causes a console window to appear on start up so you can inspect what's happening and see errors).
[HttpGet("MyEndPointA")
Then Swagger is able to generate the documentation correctly.
Solved issue in dotNet 6! Just change the attribute order of [ApiController]
In my case, there were 2 methods in the Controller class, which had the same annotations, and URL. (Our team was using Entity Framework, ASP.NET and Swagger.)
[HttpGet("GetMyGreatData/{patientId}")]
[ValidatePatient]
public async Task<ActionResult<ServiceResponse<IEnumerable<MyGreatModel>>>> GetMyGreatData(
[FromRoute] int patientId, int offset = 0, int limit = 0)
{
//method details...
}
[HttpGet("GetMyGreatData/{patientId}")]
[ValidatePatient]
public async Task<ActionResult<ServiceResponse<IEnumerable<MyGreatModel>>>> GetMyGreatData(
[FromRoute] int patientId,
[FromQuery] DateTimeOffset? startdate = null,
[FromQuery] DateTimeOffset? endDate = null,
int offset = 0,
int limit = 0)
{
//method details...
}
deleting one method solved the issue for me.
I was having the same issue, the base controller was not decorated with Http and removing that has made it work.
This error can happen when you deploy an App Service to Azure. I've redeployed the App Service to Azure and the error disappeared.
When this happened to me, I tracked it down to URL path param having an underscore which it's compatible with the asp generator
Changing this:
/block-content/{machine_name}:
To this
/block-content/{machineName}:
Solved it for me
<b>make sure the name "v1" matches the path in the swagger endpoint</b>
<p>
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo {
Title = "ODAAPP",
Version = "v1" });
});
</p>
<br/>
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
"ODAAPP v1"));
enter code here
This will also happen if you use same route for multiple action methods (Overloading is OK)
In my case, the project was configured to authenticate using identity server 4 using AddPolicy() at startup.cs and there were usages of [Authorize]
I removed the things for startup.cs and usages of [Authorize]
Will update more soon
In my case I had two identicall inner classes.
Extracted them to a single one refactored the namespaces and voilá, all returned to work properly.
I have experienced the same error when I was using Swagger and also Microsoft.AspNetCore.OData. I usually try to use the latest version - but bringing it down to v 7.5.12 - did solve my issue.
Also adding following to every Action method in the Controller, makes it work with OData v8.x too: [HttpGet], [HttpPost], or [ApiExplorerSettings(IgnoreApi = true)]
I had a similar Fetch error 404 swagger/v1/swagger.json, when trying to integrate Swagger documentation in ASP.NET Core 3.1 Web API project. I tried almost all of the above suggestions but failed.
After an hour of hit-and-trial, I decided to give NSwag a try using this reference, instead of Swashbuckle and it just worked like a charm :)
I got the similar issues - the root cause is I forgot to add the annotations :-(
Reasons for this Error
i resolved this issue by this way
Use [HttpGet] attribute above the api controller method.
And, because of different versions of swashbuckle, these errors may come.
you should use the correct swagger endpoint url
v1/swagger.json or swagger/v1/swagger.json
choose above one based on the version you are using.
Note:
Use this url for reference https://myget.org/feed/domaindrivendev/package/nuget/Swashbuckle.AspNetCore.Swagger/6.2.3-preview-1963
Refer the official swagger documentation.
lot of information is there with crystal clear documents
https://swagger.io/docs/
'Multiple operations with path 'some_path' and method 'GET' '
[HttpGet]
public IActionResult Get()
{
return Ok(_userService.Get());
}
[HttpGet]
public IActionResult Get(int Id)
{
return Ok(_userService.Get(Id));
}
Just modify DataAnnotation:
[HttpGet]
public IActionResult Get()
{
return Ok(_userService.Get());
}
[HttpGet("{Id}"] //HERE
public IActionResult Get(int Id)
{
return Ok(_userService.Get(Id));
}

Categories