I am using ASP.NET Boilerplate v2.0.1 with .NET Core and Angular 2 project template.
I have multiple modules in my project that are currently served using same API endpoint. Please note, in the future I will have separate API endpoint for an individual module.
As the API endpoint is same for every module, the service proxy which is generated through NSwag will have all the modules' services.
I am having a requirement to have proxy generated based on an individual module, so for this, I thought of accomplishing using API versioning. So instead of v1, v2 etc., I will append the module name.
I have the following code:
Configuration.Modules.AbpAspNetCore()
.CreateControllersForAppServices(
typeof(Module).GetAssembly(),
"modulename"
);
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("module1", new Info { Title = "Module 1", Version = "module1" });
options.SwaggerDoc("module2", new Info { Title = "Module 2", Version = "module2" });
}
app.UseSwagger(options =>
{
options.RouteTemplate = "swagger/{documentName}/swagger.json";
});
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/module1/swagger.json", "Module 1");
options.SwaggerEndpoint("/swagger/module2/swagger.json", "Module 2");
});
This way, I am able to generate two endpoints as follows:
http://localhost:5000/swagger/module1/swagger.json
http://localhost:5000/swagger/module2/swagger.json
But both are having all the modules' information.
Please correct me or suggest a way to achieve the functionality.
It looks like you are using swashbuckle and not NSwag to generate your swagger docs. There are multiple ways to separate your docs by version, see swashbuckle documentation https://github.com/domaindrivendev/Swashbuckle.AspNetCore. The default method is to use your startup configs that you have above and decorate your methods with the corresponding ApiExplorer group name. The group name needs to match the first argument specified in the swaggerdoc config.
[ApiExplorerSettings(GroupName = "module1")] //Module 1 Method
You are also missing an 'e' in module for the second swagger endpoint.
see example: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/4bbf5cacd6ad0817b9015d699c559fd5c1cedf0d/test/WebSites/MultipleVersions/Startup.cs
To add multiple source edit the SwaggerUIOptions.
For example:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("http://<ip1>:<port>/swagger/v1/swagger.json", "ServiceName1");
c.SwaggerEndpoint("http://<ip2>:<port>/swagger/v1/swagger.json", "ServiceName2");
});
Related
I'm using Swashbuckle with ASP.NET Core 6. It serves Swagger at /swagger.
For diagnostic purposes I need to detect that path programmatically at runtime - i.e. assuming swashbuckle is serving swagger at /swagger, then I want to be able to get that path.
I've tried various approaches, but they just give me my own routes. I can't find a way to determine routes added by swashbuckle.
I tried:
// inject IEnumerable<EndpointDataSource>
// ...
var routes = _endpointDataSources.SelectMany(source => source.Endpoints);
and:
var routes = app.Services.GetRequiredService<IActionDescriptorCollectionProvider>()
.ActionDescriptors
.Items.Where(x => x.AttributeRouteInfo != null)
.Select(x => x.AttributeRouteInfo?.Template);
In both cases it enumerates all of my routes - whether they are from RazorPages or WebApi. But the swagger route is not included, even though it is running.
How do I get that path?
Based on #lonix comment, Converting to Ans.
In case UseSwagger(), it does not create any endpoint but a middleware so when you call "/swagger", it checks request for swagger document and returns swagger document if found true. but in case of MapSwagger() it actually creates endpoint.
and yes you can swap it without breaking anything.
Is there any way to configure Swagger so that it generates UI & documentation only for a certain API controller within solution, or for a group of API controllers that belong to specific module (project withing solution)?
My solution consist of 50+ projects, several of them contains many API controllers, but I need to enable Swagger only for one of them, located in specific project.
I know about [ApiExplorerSettings(IgnoreApi = true)] attribute, but this way I would need to set this attribute to all API controllers which I don't need, and I would like just to mark the specific API controller which I want to use swagger on.
Is there any way to do that?
You can use conventions for this when registering your controllers.
If you create a new IActionModelConvention, something like this:
public class WhitelistControllersConvention : IActionModelConvention
{
public void Apply(ActionModel action)
{
if (action.Controller.ControllerName == "Item")
{
action.ApiExplorer.IsVisible = true;
}
else
{
action.ApiExplorer.IsVisible = false;
}
}
}
Then use it when configuring swagger in Startup:
services.AddControllers(c =>
{
c.Conventions.Add(new WhitelistControllersConvention());
});
Then you can control which controllers get included. In my example I'm just doing it off the name (only including ItemController), but you can change that to identify the controllers that you want however you want to do it.
Is there any method to hardcode tokens into Swagger UI permanently in Local computer or Dev Environment ?
We are testing Net Core Apis and also running them through Angular 8: developing, rebuilding, writing code, testing Swagger APIs over 100 times a day each.
Looking for way, to store token below, so don't have to keep Reentering.
Can be very cumbersome, consuming time, as minutes add up.
Maybe we can read a token from external file in developer desktop. Token stays so even after computer restarts, developers are not required to reenter tokens. Perhaps in appsettings.json or any file?
Or anyway to inject code with Net Core Visual Studio Environment, that does not expose token in Source control?
Answer should run all Swagger UI and APIs ran from Angular environment,
Only in QA and Production will require entry of token
Using Angular and Net Core 2.0 C#,
I managed to do it in ASP.NET Core 5 by adding this line to startup.cs, Configure method
app.UseSwaggerUI(c =>
{
c.ConfigObject.AdditionalItems.Add("persistAuthorization","true");
});
I found this by reading this docs
And here
Adapting my other answer to your case, your setup can look like follows:
wwwroot/swashbuckle.html
<!-- your standard HTML here, nothing special -->
<script>
// some boilerplate initialisation
// Begin Swagger UI call region
configObject.onComplete = () => {
// this is the important bit, see documentation
ui.preauthorizeApiKey('api key', 'HARDCODE YOUR KEY HERE' );// key name must match the one you defined in AddSecurityDefinition method in Startup.cs
}
const ui = SwaggerUIBundle(configObject);
window.ui = ui
}
</script>
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
.........
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new Info { Title = "You api title", Version = "v1" });
c.AddSecurityDefinition("api key", new ApiKeyScheme() // key name must match the one you supply to preauthorizeApiKey call in JS
{
Description = "Authorization query string expects API key",
In = "query",
Name = "authorization",
Type = "apiKey"
});
var requirements = new Dictionary<string, IEnumerable<string>> {
{ "api key", new List<string>().AsEnumerable() }
};
c.AddSecurityRequirement(requirements);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
if (env.IsDevelopment()) // override swashbuckle index page only if in development env
{
c.IndexStream = () => File.OpenRead("wwwroot/swashbuckle.html"); // this is the important bit. see documentation https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md
}
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); // very standard Swashbuckle init
});
app.UseMvc();
}
There are different ways to deliver your key to swagger, hard-coding might be not the best, but it should hopefully get you started.
Since you indicate you only want this functionality for development environment I opted to only serve the modified file if (env.IsDevelopment()), which you, again, can tweak to your needs
you add this functionality through swashbuckle
https://cpratt.co/customizing-swagger-ui-in-asp-net-core/
Enable bearer token in Swashbuckle (Swagger document)
I am using RazorPages in ASP.NET Core v2.0, and I was wondering if anyone knows how to force the AnchorTagHelper to use lowercase?
For example, in my .cshtml mark-up, I would have the following anchor tag using the asp-page tag helper:
<a asp-page="/contact-us">Contact Us</a>
The output that I am looking for
// i want this
Contact Us
// i get this
Contact Us
To give it more context to why this is important to my web app, please imagine a long url like what you would see at stackoverflow.com
https://stackoverflow.com/questions/anchortaghelper-asp-page-to-use-lowercase
-- VS --
https://stackoverflow.com/Questions/Anchortaghelper-asp-page-to-use-lowercase
Any help would be appreciated!
I have looked at these other references but no luck:
https://github.com/aspnet/Mvc/issues/6393
How do you enforce lowercase routing in ASP.NET Core MVC 6?
Add the following to your ConfigureServices method in Startup.cs. It can be added before or after services.AddMvc();
services.AddRouting(options =>
{
options.LowercaseUrls = true;
});
Now for the anchor tag
<a asp-page="/Contact-Us">Contact Page</a>
And the output
Contact Page
It's a bit easier now, simply add this to your ConfigureServices method in Startup.cs.
services.Configure<RouteOptions>(options =>
{
options.LowercaseUrls = true;
});
The url helper that will generate the target link will use the metadata that is being generated for routes. For razor pages, this uses the exact file path to identify the route.
Starting with ASP.NET Core 2.1, you will likely be able to adjust the route just like MVC routes using the Route attribute. At least it’s planned for the 2.1 release.
Until then, you will have to configure specific routes for your pages in the ConfigureServices method:
services.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/ContactUs", "contact-us");
});
This will keep the existing route available for use, so if you do not want that, you will need to replace the route selector for this page. There is no built-in way to do this, but it’s not too difficult to do it when you know what to do.
To avoid code duplication and to make everything nicer, we’ll just create a ReplacePageRoute extension method, that basically matches the usage of the AddPageRoute above:
services.AddMvc()
.AddRazorPagesOptions(options => {
options.Conventions.ReplacePageRoute("/Contact", "contact-us");
});
The implementation of that method is directly inspired by that AddPageRoute:
public static PageConventionCollection ReplacePageRoute(this PageConventionCollection conventions, string pageName, string route)
{
if (conventions == null)
throw new ArgumentNullException(nameof(conventions));
if (string.IsNullOrEmpty(pageName))
throw new ArgumentNullException(nameof(pageName));
if (route == null)
throw new ArgumentNullException(nameof(route));
conventions.AddPageRouteModelConvention(pageName, model =>
{
// clear all existing selectors
model.Selectors.Clear();
// add a single selector for the new route
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = route,
}
});
});
return conventions;
}
I have a solution in VS2013 with several class libraries and a Web API project. I am running into a few problems when setting up Swagger UI. First, when I setup swashbuckle for my Web API project, I can only point to one documentation XML file. Is there a way to point to include multiple XML files so that Swagger not only picks up documentation for my routes in controller but also the domain objects from my other projects as well? Here is my code from SwaggerConfig.cs
SwaggerSpecConfig.Customize
(
c =>
{
c.IncludeXmlComments(Path.Combine(dirPath, projName + ".xml"));
}
);
If I add multiple XML files, it only picks up the last file from IncludeXmlComments.
Second, I am using camel case for my DTOs when returning in JSON
formats.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
However when I look at the response model and model schema in Response Class in Swagger UI, I see the exact class property names instead of the JSON schema which is returned when an endpoint is hit. Is there a way to show the exact JSON schema in the Swagger UI documentation page?
I am using version 5.6.0 and multiple XML docs works for me:
var dir = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
foreach (var fi in dir.EnumerateFiles("*.xml"))
{
c.IncludeXmlComments(fi.FullName);
}
to add multiple XML File configure swagger like that.
SwaggerSpecConfig.Customize(c =>
{
// single XML Comment Files
//c.IncludeXmlComments(GetXmlCommentsPath());
// Multiple XML Comment Files
string[] paths = GetXmlCommentsPaths();
foreach (string xmlCommentsPath in paths)
{
c.OperationFilter(new ApplyActionXmlComments(xmlCommentsPath))
.ModelFilter(new ApplyTypeXmlComments(xmlCommentsPath));
}
});
After version 4.1 you can write this:
c.IncludeXmlComments("File1_Path");
c.IncludeXmlComments("File2_Path"));
See also here.