NSwag: 404 Not Found /swagger/v1/swagger.json on IIS - swagger

I have a basic asp.net core 2.1 web API. I installed NSwag.ASPNetCore nuget package.
here is my startup.cs. When I run this on IIS Express, swagger is working fine.
Once I deploy this to IIS, I am getting 404 not found.
Do I need to add a Path somewhere?
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddMvc();
// Add framework services.
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//Add Application Services
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSwaggerDocument();
}
// 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("CorsPolicy");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUi3();
app.UseMvc();
}
}

As mentioned by Rico below: upgrading to nswag v13 should fix the issue (for me it worked).
For versions of nswag before v13:
I had the same problem and I found a solution here: NSwag Issue #1914
What you need to do is configure a 'transform to external path':
app.UseSwaggerUi3(config =>
{
config.TransformToExternalPath = (s, r) =>
{
string path = s.EndsWith("swagger.json") && !string.IsNullOrEmpty(r.PathBase)
? $"{r.PathBase}{s}"
: s;
return path;
};
});
This worked for me on my iisexpress and on iis.

Check if you do not use Virtual Path for the application. Swagger by default checks absolute path instead of
localhost:port/MyVirtualPath/swagger/v1/swagger.json
It may happen when you use IIS server with virtual path delimiter.

Related

create sub domains "sub.example.com" with .net core 5

i'm trying to create a sub domain for my website, something like "sub.example.com", i've been following a tutorial on youtube but it is not working, this is what i have done.
my startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<SubdomainRouteTransformer>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapDynamicControllerRoute<SubdomainRouteTransformer>(
"{controller=Home}/{action=Index}/{id?}");
});
public class SubdomainRouteTransformer: DynamicRouteValueTransformer
{
public override async ValueTask<RouteValueDictionary> TransformAsync(
HttpContext httpContext,RouteValueDictionary values)
{
var host =httpContext.Request.Host.Value;
var subdomain = httpContext.Request.Host.Value.Split(".")[0];
if(!string.IsNullOrEmpty(subdomain)){
values["controller"]= subdomain;
}
return values;
}
}
program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("https://*.localhost:5001");
});
i have also registred new subdomains on my machine hosts file
127.0.0.1 admin.localhost
127.0.0.1 bugreport.localhost
i tried to create a break point on the TransformAsync method, it is getting hit by the compiler whenever i enter the normal URL address "https://localhost:5001".
when i enter sub domain address "https://admin.localhost:5001" TransformAsync method is never getting hit .
any help is appreciated
i've figured out this by myself, it seams like the solution above is working perfectly, the issue was with Safari, somehow the solution above did not work on it but it worked perfectly on chrome.
also another small detail is that you can skip the last step of setting the host file on your machine, the solution works without it.

Facing issue with configure method in .Net core application

I have developed .Net core API project and deployed on the server.
I added it as site on IIS(remote windows server)and tried to browse the application.
The application is not working properly facing issue at Configure method
Here is my configure method in >net core
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var appName = "";
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
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", "Api V1");
});
}
Please let me know how can to add swagger endpoint.
I guess you directly publish your web application to a nested site in the default website on IIS.
So the "/swagger/v1/swagger.json" root path will become localhost/swagger/v1/swagger.json not localhost/yourwebsitename/swagger/v1/swagger.json.
To solve this issue, I suggest you could try to modify the SwaggerEndpoint path as this `c.SwaggerEndpoint("../swagger/v1/swagger.json", "Api V1");.
More details, you could refer to below startup.cs
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", "Api V1");
});
`

How to register OData extension methods in .NetCore 3.1 outside of UseMvc middleware

After migrating my API from .net core 2.2 to 3.1, I am facing some issues to decide which is the best approach I should follow to register OData extension methods for my API. Currently, I have this code
public void ConfigureServices(IServiceCollection services)
{
....
#region OData
services.AddOData();
#endregion
....
}
On the Configure method
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
...
app.UseAuthentication();
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().OrderBy().Filter().MaxTop(1000).Count();
routeBuilder.EnableDependencyInjection();
});
...
}
How can I register Select() OrderBy() Filter() .... using the following approach? Is this the right way to do it, without registering UseMvc?
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
...
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
...
}
Check this article out: Experimenting with OData in ASP.NET Core 3.1.
Apparently .NET Core 3.0 and 3.1 don't support OData yet. You can, however, use the beta version, the steps for which is explained in the article.
Update:
They do support OData as of version 7.3.0. However, they cannot be used with endpoint routing yet. You can follow this Github thread for updates, in particular, this answer

gRPC and MVC in same ASP.NET Core 3.0 Application

I am building out small, single purpose micro-services that require access via gRPC and Rest. We are implementing on ASP.NET Core 3.0. I realize this is pretty fresh stuff and have been looking for some reasonably complete reference implementations that demonstrate how to get this done.
I have a small .NET Service (Business Logic) call it IOrders. Now I want to wire up both gRPC and MVC (HTTP) against this back end service.
Any examples, github repos, blogs to follow or look around in would be greatly appreciated.
I had exactly same issue. I am runing.NET Core 3.0 and Grpc.AspNetCore Version 2.23.1. The biggest problem was to start it without SSL (not recommended for prod environments). Using certificate i found this github Secure_gRpc to be nice example.
Running without ssl for dev environments could be achieved in this way.
Program.cs file. Key aspects is to set HttpProtocols.Http1AndHttp2. I also removed certificate just to get it running. Uncomment next line to use SSL and certificate
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.ConfigureKestrel(options =>
{
options.Limits.MinRequestBodyDataRate = null;
options.ListenLocalhost(8008, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(adapterOptions =>
{
adapterOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
adapterOptions.ServerCertificate = null;
});
//listenOptions.UseHttps("<path to .pfx file>", "<certificate password>");
});
});
});
}
Startup.cs is pretty straightforward. It is very important to remember if you modify Startup.cs file order of added services is very important. If it doesnt work try other order and/or find official documentation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc((options => { options.EnableDetailedErrors = true; }));
services.AddMvc(options => options.EnableEndpointRouting = false);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseMvcWithDefaultRoute();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
}

Issue Using Custom Index.Html in Swagger / Swashbuckle for .NET Core

I am having difficulty using a custom index.html and other assets with swashbuckle. Swashbuckle/Swagger do not seem to recognizing or using them at all. I do have app.UseDefaultFiles() and app.UseStaticFiles() set. I am trying to understand what I am doing incorrectly.
I have attempted to set up my configuration somewhat similar to what is defined on the Microsoft article without success. (https://learn.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?tabs=visual-studio)
I am presently using the files from the dist folder referenced in the article (https://github.com/swagger-api/swagger-ui/tree/2.x/dist) along with the custom css file provided.
My index.html file is located under /wwwroot/swagger/ui
The custom css file is located under /wwwroot/swagger/ui/css (as custom.css)
Here is my Startup.cs class.
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()
.AddJsonOptions(options =>
{
// Swagger - Format JSON
options.SerializerSettings.Formatting = Formatting.Indented;
});
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.DescribeAllEnumsAsStrings();
c.DescribeStringEnumsInCamelCase();
// c.DescribeAllParametersInCamelCase();
c.SwaggerDoc("v1",
new Info
{
Title = "My Web API - v1",
Version = "v1",
Description = "New and improved version. A simple example ASP.NET Core Web API. "
}
);
c.SwaggerDoc("v2",
new Info
{
Title = "My Web API - v2",
Version = "v2",
Description = "New and improved version. A simple example ASP.NET Core Web API. "
}
);
// Set the comments path for the Swagger JSON and UI.
var basePath = AppContext.BaseDirectory;
var xmlPath = Path.Combine(basePath, "ApiTest.xml");
c.IncludeXmlComments(xmlPath);
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
string swaggerUIFilesPath = env.WebRootPath + "\\swagger\\ui";
if (!string.IsNullOrEmpty(swaggerUIFilesPath))
{
app.UseDefaultFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(swaggerUIFilesPath),
RequestPath = new PathString("/api-docs"),
});
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(c =>
{
c.RouteTemplate = "api-docs/{documentName}/swagger.json";
});
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
//c.ShowJsonEditor();
c.RoutePrefix = "api-docs";
c.SwaggerEndpoint("/api-docs/v1/swagger.json", "My Web API - V1 ");
c.SwaggerEndpoint("/api-docs/v2/swagger.json", "My Web API - V2 ");
c.DocumentTitle("My Web API");
});
app.UseMvc();
}
}
My ultimate objective is to be able to use something like the slate style theme available here (https://github.com/omnifone/slate-swagger-ui). For right now, I am just trying to get Swashbuckle/Swagger to use the customized files referenced in the Microsoft documentation before trying to make the other files work.
I really do NOT want to try and convert my assets to embedded resources--since there will many of them. I just want to reference a normal index.html file and be able to use all of its referenced files.
What am I doing wrong?
Relevant Software Versions
.Net Core Version: 2.0.3
Swashbuckle.AspNetCore: 1.2.0
Windows 10 Enterprise Build 1703
Visual Studio 2017 Enterprise 15.5.2
Here is the minimum action I found to be necessary to replace SwashBuckle's index.html in a .NET Core project:
Get a copy of the original index.html from here: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.SwaggerUI/index.html
Place that copy in some sub-folder of your project.
The file may have a different name, I chose:
\Resources\Swagger_Custom_index.html
Right-click that file in Solution Explorer, select 'Properties', select 'Configuration Properties' in left pane. Under 'Advanced' in right pane find entry 'Build Action' and set it to 'Embedded resource'. Click Ok.
In Startup.cs add the following line to your app.UseSwaggerUI() call:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
app.UseSwaggerUI(c =>
{
c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Your.Default.Namespace.Resources.Swagger_Custom_index.html");
});
//...
}
The identifier for the file resource in the above GetManifestResourceStream method is composed of:
your default namespace (i.e. 'Your.Default.Namespace')
the sub-path of your resource (i.e. 'Resources')
the filename of your resource (i.e. 'Swagger_Custom_index.html')
All three parts are concatenated using dots (NO slashes or backslashes here).
If you don't use a sub-path but have your resource in root, just omit part 2.
For people who separate ApplicationBuilder config methods on ASP.NET Core:
If the separated method/class is static, it is not possible to call GetType() because an object reference is required.
In that case, switch GetType() to MethodBase.GetCurrentMethod().DeclaringType
c.IndexStream = () => MethodBase.GetCurrentMethod().DeclaringType.Assembly.GetManifestResourceStream("xxx.index.html");

Resources