First install the following NuGet package into your ASP.NET Core application.
dotnet add package Swashbuckle.AspNetCore.Annotations
Next in your application's startup path, enable annotations within the Swagger configuration callback:
services.AddSwaggerGen(options =>
{
// Other setup, then...
options.EnableAnnotations();
});Once annotations have been enabled, you can enrich the generated Operation metadata by decorating actions with [SwaggerOperation].
[HttpPost]
[SwaggerOperation(
Summary = "Creates a new product",
Description = "Requires admin privileges",
OperationId = "CreateProduct",
Tags = ["Purchase", "Products"]
)]
public IActionResult Create([FromBody] Product product)
{
//...
return Ok();
}ASP.NET Core provides the ProducesResponseTypeAttribute for listing the different responses that
can be returned by an action. These attributes can be combined with XML comments, as described
further here, to
include human-friendly descriptions with each response in the generated document. If you'd prefer
to do all of this with a single attribute, and avoid the use of XML comments, you can use one or more [SwaggerResponse] instead:
[HttpPost]
[SwaggerResponse(201, "The product was created", typeof(Product))]
[SwaggerResponse(400, "The product data is invalid")]
public IActionResult Post([FromBody] Product product)
{
//...
return Created();
}You can annotate path, query or header-bound parameters or properties (i.e. decorated with [FromRoute], [FromQuery]
or [FromHeader]) with a SwaggerParameterAttribute to enrich the corresponding Parameter metadata that's generated by Swashbuckle.AspNetCore:
[HttpGet]
public IActionResult GetProducts(
[FromQuery, SwaggerParameter("Search keywords", Required = true)] string keywords)
{
//...
return Ok();
}You can annotate body-bound parameters or properties (i.e. decorated with [FromBody]) with [SwaggerRequestBody] to enrich
the corresponding RequestBody metadata that's generated by Swashbuckle.AspNetCore:
[HttpPost]
public IActionResult SubmitProduct(
[FromBody, SwaggerRequestBody("The product payload", Required = true)] Product product)
{
//...
return Created();
}You can annotate classes or properties with [SwaggerSchema] to enrich the corresponding Schema metadata that's generated by Swashbuckle.AspNetCore:
[SwaggerSchema(Required = ["Description"])]
public class Product
{
[SwaggerSchema("The product identifier", ReadOnly = true)]
public int Id { get; set; }
[SwaggerSchema("The product description")]
public string Description { get; set; } = string.Empty;
[SwaggerSchema("The date it was created", Format = "date")]
public DateTime DateCreated { get; set; }
}Note
In OpenAPI, serialized objects and contained properties are represented as Schema instances, hence why this annotation can
be applied to both classes and properties. Also, required properties are specified as an array of property names on the top-level schema
as opposed to a flag on each individual property.
The Swashbuckle.AspNetCore.SwaggerGen NuGet package provides several extension points, including
Schema Filters for
customizing all generated Schemas. However, there may be cases where it's preferable to apply a filter to a specific
Schema. For example, if you'd like to include an example for a specific type in your API. This can be done by decorating the
type with [SwaggerSchemaFilter]:
📝 Item.cs
[SwaggerSchemaFilter(typeof(ItemSchemaFilter))]
public class Item
{
//...
}📝 ItemSchemaFilter.cs
public class ItemSchemaFilter : ISchemaFilter
{
public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
{
if (schema is OpenApiSchema concrete)
{
concrete.Example = new JsonObject
{
["Id"] = 1,
["Description"] = "An awesome item"
};
}
}
}By default, the OpenAPI generator will tag all operations with the controller name for MVC applications. This tag is then
used to drive the operation groupings in swagger-ui. If you'd like to provide
a description for each of these groups, you can do so by adding metadata for each controller name tag using [SwaggerTag]:
[SwaggerTag("Create, read, update and delete Items")]
public class ItemsController
{
//...
}Note
This will add the above description specifically to the tag named Items. Therefore, you should avoid using this attribute
if you're tagging Operations with something other than the controller name - e.g. if you're customizing the tagging behavior with TagActionsBy.
If you want to use Swashbuckle's inheritance and/or polymorphism behavior, you can use annotations to explicitly indicate the "known" subtypes for a given base type. This will override the default selector function, which selects all subtypes in the same assembly as the base type, and therefore needs to be explicitly enabled when you enable Annotations:
📝 Startup.cs
services.AddSwaggerGen(options =>
{
options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});📝 Shape.cs
[JsonDerivedType(typeof(Rectangle))]
[JsonDerivedType(typeof(Circle))]
public abstract class Shape
{
}If you're using annotations to explicitly indicate the "known" subtypes for a polymorphic base type, you can combine
[JsonPolymorphic] with [JsonDerivedType] to provide additional metadata about the "discriminator" property, which will
then be incorporated into the generated schema definition:
📝 Startup.cs
services.AddSwaggerGen(options =>
{
options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});📝 ShapeWithDiscriminator.cs
[JsonPolymorphic(TypeDiscriminatorPropertyName = "shapeType")]
[JsonDerivedType(typeof(Rectangle), "rectangle")]
[JsonDerivedType(typeof(Circle), "circle")]
public abstract class ShapeWithDiscriminator
{
// Avoid using a JsonPolymorphicAttribute.TypeDiscriminatorPropertyName
// that conflicts with a property in your type hierarchy.
// Related issue: https://github.com/dotnet/runtime/issues/72170
}
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ShapeType
{
Circle,
Rectangle
}This indicates that the corresponding payload will have a "shapeType" property to discriminate between subtypes, and that property
will have a value of "rectangle" if the payload represents a Rectangle type and a value of "circle" if it represents a Circle type.
This detail will be described in the generated schema definition as follows:
schema: {
oneOf: [
{
$ref: "#/components/schemas/Rectangle"
},
{
$ref: "#/components/schemas/Circle"
},
],
discriminator: {
propertyName: shapeType,
mapping: {
rectangle: "#/components/schemas/Rectangle",
circle: "#/components/schemas/Circle",
}
}
}