Unchase Swashbuckle Asp.Net Core Extensions is a library contains a bunch of extensions (filters) for Swashbuckle.AspNetCore.
The project is developed and maintained by Nikolay Chebotov (Unchase).
- Since v2.0.0 supports Swashbuckle.AspNetCore 5.0.0 with breaking changes.
For old versions see README_OLD.md.
- Since v2.3.0 there are breaking changes in
Startup.cs
Swashbuckle Version | ASP.NET Core | Swagger / OpenAPI Spec. | This extension Version |
---|---|---|---|
master | >= 2.0.0 | 2.0, 3.0 | master |
6.1.5 | >= 2.0.0 | 2.0, 3.0 | v2.6.1 |
6.1.0 | >= 2.0.0 | 2.0, 3.0 | v2.6.0 |
6.0.0 | >= 2.0.0 | 2.0, 3.0 | v2.5.1 |
5.0.0 | >= 2.0.0 | 2.0, 3.0 | v2.0.0 |
4.0.0 | >= 2.0.0, < 3.0.0 | 2.0 | v1.1.4 |
To use the extensions, install NuGet package into your project:
Install-Package Unchase.Swashbuckle.AspNetCore.Extensions
dotnet add package Unchase.Swashbuckle.AspNetCore.Extensions --version {version}
Where {version} is the version of the package you want to install. For example,
dotnet add package Unchase.Swashbuckle.AspNetCore.Extensions --version 2.4.0
Then use whichever extensions (filters) you need.
Ensure your API actions and parameters are decorated with explicit "Http" and "From" (optional) bindings.
[HttpPost]
public void CreateProduct([FromBody]Product product)
...
[HttpGet]
public IEnumerable<Product> SearchProducts([FromQuery]string keywords)
...
In the Configure
method, insert middleware to expose the generated Swagger as JSON endpoint(s):
app.UseSwagger();
Optionally, insert the swagger-ui middleware if you want to expose interactive documentation, specifying the Swagger JSON endpoint(s) to power it from:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
- Fix enums in OpenApi document:
- In the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, enable whichever extensions (filters) you need:
using Unchase.Swashbuckle.AspNetCore.Extensions.Extensions;
using Unchase.Swashbuckle.AspNetCore.Extensions.Filters;
- Since v2.3.0:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddControllers();
// Register the Swagger generator
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// use it if you want to hide Paths and Definitions from OpenApi documentation correctly
options.UseAllOfToExtendReferenceSchemas();
// if you want to add xml comments from summary and remarks into the swagger documentation, first of all add:
// you can exclude remarks for concrete types
var xmlFilePath = Path.Combine(AppContext.BaseDirectory, "WebApi3.1-Swashbuckle.xml");
options.IncludeXmlCommentsWithRemarks(xmlFilePath, false,
typeof(ComplicatedClass),
typeof(InnerEnum));
// or add without remarks
//options.IncludeXmlComments(xmlFilePath);
// if you want to add xml comments from inheritdocs (from summary and remarks) into the swagger documentation, add:
// you can exclude remarks for concrete types
options.IncludeXmlCommentsFromInheritDocs(includeRemarks: true, excludedTypes: typeof(string));
// Add filters to fix enums
// use by default:
//options.AddEnumsWithValuesFixFilters();
// or configured:
options.AddEnumsWithValuesFixFilters(services, o =>
{
// add schema filter to fix enums (add 'x-enumNames' for NSwag or its alias from XEnumNamesAlias) in schema
o.ApplySchemaFilter = true;
// alias for replacing 'x-enumNames' in swagger document
o.XEnumNamesAlias = "x-enum-varnames";
// alias for replacing 'x-enumDescriptions' in swagger document
o.XEnumDescriptionsAlias = "x-enum-descriptions";
// add parameter filter to fix enums (add 'x-enumNames' for NSwag or its alias from XEnumNamesAlias) in schema parameters
o.ApplyParameterFilter = true;
// add document filter to fix enums displaying in swagger document
o.ApplyDocumentFilter = true;
// add descriptions from DescriptionAttribute or xml-comments to fix enums (add 'x-enumDescriptions' or its alias from XEnumDescriptionsAlias for schema extensions) for applied filters
o.IncludeDescriptions = true;
// add remarks for descriptions from xml-comments
o.IncludeXEnumRemarks = true;
// get descriptions from DescriptionAttribute then from xml-comments
o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;
// new line for enum values descriptions
// o.NewLine = Environment.NewLine;
o.NewLine = "\n";
// get descriptions from xml-file comments on the specified path
// should use "options.IncludeXmlComments(xmlFilePath);" before
o.IncludeXmlCommentsFrom(xmlFilePath);
// the same for another xml-files...
});
});
}
- For older versions:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// if you want to add xml comments into the swagger documentation, first of all add:
var filePath = Path.Combine(AppContext.BaseDirectory, "WebApi3.1-Swashbuckle.xml");
options.IncludeXmlComments(filePath);
// Add filters to fix enums
options.AddEnumsWithValuesFixFilters(true);
// or custom use:
//options.SchemaFilter<XEnumNamesSchemaFilter>(true); // add schema filter to fix enums (add 'x-enumNames' for NSwag) in schema
//options.ParameterFilter<XEnumNamesParameterFilter>(true); // add parameter filter to fix enums (add 'x-enumNames' for NSwag) in schema parameters
//options.DocumentFilter<DisplayEnumsWithValuesDocumentFilter>(true); // add document filter to fix enums displaying in swagger document
});
}
- Hide Paths and Definitions from OpenApi documentation without accepted roles:
- In the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, enableHidePathsAndDefinitionsByRolesDocumentFilter
document filter:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// remove Paths and Defenitions from OpenApi documentation without accepted roles
options.DocumentFilter<HidePathsAndDefinitionsByRolesDocumentFilter>(new List<string> { "AcceptedRole" });
});
}
- Since v2.2.1 you can hide Paths and Definitions from OpenApi documentation for specific controller action (or all actions) without accepted roles like this:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
// enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((openApiDoc, httpRequest) =>
{
// remove Paths and Components from OpenApi documentation for specific controller action without accepted roles
openApiDoc.RemovePathsAndComponentsWithoutAcceptedRolesFor<SomeController>(controller => nameof(controller.SomeAction), new List<string> {"AcceptedRole"});
// or
//openApiDoc.RemovePathsAndComponentsWithoutAcceptedRolesFor<SomeController>(nameof(SomeController.SomeAction), new List<string> { "AcceptedRole" });
// remove Paths and Components from OpenApi documentation for all controller actions without accepted roles
openApiDoc.RemovePathsAndComponentsWithoutAcceptedRolesForController<AnotherController>(new List<string> {"AcceptedRole"});
// or you can get accepted roles by httpRequest like this:
//openApiDoc.RemovePathsAndComponentsWithoutAcceptedRolesForController<AnotherController>(GetAcceptedRolesByRemoteIp(httpRequest.HttpContext.Connection.RemoteIpAddress));
});
});
//...
}
Validated actions must be annotated with the one of HttpMethodAttribute
(HttpGetAttribute
, HttpPostAttribute
, HttpDeleteAttribute
, HttpPutAttribute
, HttpPatchAttribute
) attributes.
- Append action count into the SwaggetTag's descriptions in OpenApi document:
- In the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, enableAppendActionCountToTagSummaryDocumentFilter
document filter:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// enable openApi Annotations
options.EnableAnnotations();
// add action count (with message template) into the SwaggerTag's descriptions
// you can use it after "HidePathsAndDefinitionsByRolesDocumentFilter"
options.DocumentFilter<AppendActionCountToTagSummaryDocumentFilter>("(count: {0})");
...
});
}
In the controller need to use SwaggerTag
attribute:
using Swashbuckle.AspNetCore.Annotations;
[SwaggerTag("Controller for todo")]
public class TodoController : ControllerBase
...
- Change all responses for specific HTTP status codes in OpenApi document:
- In the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, enableChangeAllResponsesByHttpStatusCode<T>
extension (filter) with whichever HTTP status codes you need:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// change responses for specific HTTP status code ("200")
options.ChangeAllResponsesByHttpStatusCode(
httpStatusCode: 200,
responseDescription: "200 status code description",
responseExampleOption : ResponseExampleOptions.AddNew, // add new response examples
responseExample: new TodoItem { Tag = Tag.Workout, Id = 111, IsComplete = false, Name = "test" }); // some class for response examples
// change responses for specific HTTP status code ("400" (HttpStatusCode.BadRequest))
options.ChangeAllResponsesByHttpStatusCode(
httpStatusCode: HttpStatusCode.BadRequest,
responseDescription: "400 status code description",
responseExampleOption: ResponseExampleOptions.Clear, // claer response examples
responseExample: new ComplicatedClass()); // some class for response examples
// change responses for specific HTTP status code ("201" (StatusCodes.Status201Created))
options.ChangeAllResponsesByHttpStatusCode(
httpStatusCode: StatusCodes.Status201Created,
responseDescription: "201 status code description",
responseExampleOption: ResponseExampleOptions.None, // do nothing with response examples
responseExample: new ComplicatedClass()); // some class for response examples
...
});
}
- Order tags by name in OpenApi document:
- In the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, enableTagOrderByNameDocumentFilter
document filter:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// order tags by name
options.DocumentFilter<TagOrderByNameDocumentFilter>();
...
});
}
- Add xml comments from summary and remarks into the swagger documentation:
- Since v2.4.0 in the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, addIncludeXmlCommentsWithRemarks
option instead ofIncludeXmlComments
option:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// add xml comments from summary and remarks into the swagger documentation
options.IncludeXmlCommentsWithRemarks("<xml_File_Full_Path>");
// add xml comments from summary and remarks into the swagger documentation
// with excluding remarks for concrete types (since v2.4.1)
var xmlFilePath = Path.Combine(AppContext.BaseDirectory, "WebApi3.1-Swashbuckle.xml");
options.IncludeXmlCommentsWithRemarks(xmlFilePath, false,
typeof(ComplicatedClass),
typeof(InnerEnum));
...
});
}
- Add xml comments from <inheritdoc/> (from summary and remarks) into the swagger documentation:
- Since v2.5.0 in the ConfigureServices method of Startup.cs, inside your
AddSwaggerGen
call, addIncludeXmlCommentsFromInheritDocs
option:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(options =>
{
...
// add xml comments from inheritdocs (from summary and remarks) into the swagger documentation, add:
// with excluding concrete types
options.IncludeXmlCommentsFromInheritDocs(includeRemarks: true, excludedTypes: typeof(string));
...
});
}
Status | Value |
---|---|
Build | |
Tests | |
Buid History | |
GitHub Release | |
GitHub Release Date | |
GitHub Release Downloads | |
Nuget Version | |
Nuget Downloads |
-
Add an output enums integer values with there strings like
0 = FirstEnumValue
without aStringEnumConverter
in swaggerUI and schema (by default enums will output only their integer values) -
Add description to each enum value that has an
[Description]
attribute inswaggerUI
and schema - should use options.DocumentFilter<DisplayEnumsWithValuesDocumentFilter>(true); or options.AddEnumsWithValuesFixFilters(true);In schema
parameters
:In schema
definitions
:To show enum values descriptions you should use
[Description]
attribute in your code:/// <summary> /// Title enum. /// </summary> [DataContract] public enum Title { /// <summary> /// None. /// </summary> [Description("None enum description")] [EnumMember] None = 0, /// <summary> /// Miss. /// </summary> [Description("Miss enum description")] [EnumMember] Miss, /// <summary> /// Mr. /// </summary> [Description("Mr enum description")] [EnumMember] Mr } ... /// <summary> /// Sample Person request and response. /// </summary> public class SamplePersonRequestResponse { /// <summary> /// Sample Person title. /// </summary> public Title Title { get; set; } /// <summary> /// Sample Person age. /// </summary> public int Age { get; set; } /// <summary> /// Sample Person firstname. /// </summary> [Description("The first name of the person")] public string FirstName { get; set; } /// <summary> /// Sample Person income. /// </summary> public decimal? Income { get; set; } }
-
Fix enum values in generated by
NSwagStudio
or Unchase OpenAPI Connected Service client classes:/// <summary>Sample Person title. /// /// 0 = None (None enum description) /// /// 1 = Miss (Miss enum description) /// /// 2 = Mr (Mr enum description)</summary> [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.13.35.0 (Newtonsoft.Json v11.0.0.0)")] public enum Title { None = 0, Miss = 1, Mr = 2, }
-
Hide all OpenAPIDocument Paths and Defenitions without accepted roles:
You should use
AuthorizeAttribute
for methods or controllers:... public class SamplePersonController : ControllerBase { // this method will not be hidden with using 'swaggerDoc.HidePathItemsWithoutAcceptedRoles(new List<string> {"AcceptedRole"});' [Authorize(Roles = "AcceptedRole")] [HttpGet] public ActionResult<SamplePersonRequestResponse> Get(Title title) { ... } // this method will be hidden with using 'swaggerDoc.HidePathItemsWithoutAcceptedRoles(new List<string> {"AcceptedRole"});' [Authorize(Roles = "NotAcceptedRole")] [HttpPost] public ActionResult<SamplePersonRequestResponse> Post([FromBody] SamplePersonRequestResponse request) { ... } }
You should use SwaggerTagAttribute
for controllers:
[SwaggerTag("SamplePerson description")]
public class SamplePersonController : ControllerBase
{
...
}
For example:
For code:
/// <summary>
/// Inner class
/// </summary>
/// <remarks>
/// Inner class remarks - class
/// </remarks>
public class InnerClass
{
/// <summary>
/// List of inner enums
/// </summary>
/// <remarks>
/// List of inner enums remarks - property
/// </remarks>
public List<InnerEnum> InnerEnum { get; set; }
/// <summary>
/// Second inner class
/// </summary>
/// <remarks>
/// Second inner class remarks - property
/// </remarks>
public SecondInnerClass<SecondInnerEnum> SecondInnerClass { get; set; }
}
/// <summary>
/// Inner enum
/// </summary>
/// <remarks>
/// Inner enum remarks - enum
/// </remarks>
public enum InnerEnum
{
/// <summary>
/// Inner enum value
/// </summary>
/// <remarks>
/// Inner enum value remarks
/// </remarks>
Value = 1
}
/// <summary>
/// Second inner class
/// </summary>
/// <remarks>
/// Second inner class remarks - class
/// </remarks>
public class SecondInnerClass<T> where T : Enum
{
/// <summary>
/// Second inner enum
/// </summary>
/// <remarks>
/// Second inner enum remarks - property
/// </remarks>
public T InnerEnum { get; set; }
}
/// <summary>
/// Second inner enum
/// </summary>
/// <remarks>
/// Second inner enum remarks - enum
/// </remarks>
public enum SecondInnerEnum
{
/// <summary>
/// Second inner enum value
/// </summary>
/// <remarks>
/// Second inner enum value remarks
/// </remarks>
Value = 0
}
For code:
/// <inheritdoc cref="IInheritDocClass"/>
public class InheritDocClass : IInheritDocClass
{
/// <inheritdoc/>
public string Name { get; set; }
/// <inheritdoc/>
public string Common { get; set; }
/// <inheritdoc/>
public InheritEnum InheritEnum { get; set; }
}
/// <summary>
/// InheritDocClass - inheritdoc
/// </summary>
/// <remarks>
/// InheritDocClass remarks - inheritdoc
/// </remarks>
public interface IInheritDocClass : IInheritDocCommon
{
/// <summary>
/// Name - inheritdoc
/// </summary>
/// <remarks>
/// Name remarks - inheritdoc
/// </remarks>
public string Name { get; set; }
}
/// <summary>
/// IInheritDocCommon interface
/// </summary>
/// <remarks>
/// IInheritDocCommon interface remarks
/// </remarks>
public interface IInheritDocCommon
{
/// <summary>
/// Common - inheritdoc (inner)
/// </summary>
/// <remarks>
/// Common remarks - inheritdoc (inner)
/// </remarks>
public string Common { get; set; }
/// <summary>
/// InheritEnum - inheritdoc (inner)
/// </summary>
public InheritEnum InheritEnum { get; set; }
}
/// <summary>
/// Inherit enum - enum
/// </summary>
/// <remarks>
/// Inherit enum remarks - enum
/// </remarks>
public enum InheritEnum
{
/// <summary>
/// Inherit enum Value
/// </summary>
/// <remarks>
/// Inherit enum Value remarks
/// </remarks>
Value = 0
}
- Add HowTos in a future
- ... request for HowTo you need
See the changelog for the further development plans and version history.
Please feel free to add your request a feature or report a bug. Thank you in advance!
If you like what I am doing and you would like to thank me, please consider:
Thank you for your support!
Copyright © 2019 Nikolay Chebotov (Unchase) - Provided under the Apache License 2.0.