How can I set swagger operationId
attribute in Asp.Net Core 2.1 project? According to this post I should use SwaggerOperationAttribute
but I cannot find it in Swashbuckle.AspNetCore library. Also there is an IOperationFilter
public interface IOperationFilter
{
void Apply(Operation operation, OperationFilterContext context);
}
and I can't find any implementations for swagger generation purposes.
There are 2 other options without having to write any extra code or add extra dependency like Swashbuckle.AspNetCore.Annotations
Option 1: Convention based - SwaggerGen
has an option to set CustomOperationIds
. So you can simply set it to use ControllerName_HttpMethod
like this:
services.AddSwaggerGen(c =>
{
c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
c.SwaggerDoc("v1", new Info { Title = "Test API", Version = "v1" });
});
This will add operationIds to all your methods, following ControllerName_HttpMethod
convention.
Option 2: ActionFilter/Attribute based - you can configure each Action method (as you'd do with SwaggerOperation
action filter by simple adding a Name
property to your HTTP verb action filter like this:
[HttpPost(Name="Post_Person")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<ActionResult<Response>> PostAsync([FromBody]Request request)
{
Response result = await _context.PostAsync(request);
return Ok(result);
}
This works exactly like [SwaggerOperation(OperationId = "Post_Person")]
but without the need of EnableAnnotations
You can enable annotation on swagger with the Swashbuckle.AspNetCore.Annotations nuget package. (https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#swashbuckleaspnetcoreannotations)
Once annotations have been enabled, you can enrich the generated Operation metadata by decorating actions with a SwaggerOperationAttribute.
[HttpPost]
[SwaggerOperation(
Summary = "Creates a new product",
Description = "Requires admin privileges",
OperationId = "CreateProduct",
Tags = new[] { "Purchase", "Products" }
)]
public IActionResult Create([FromBody]Product product)
Finally, I came to this solution:
public class SwaggerOperationNameFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
operation.OperationId = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
.Union(context.MethodInfo.GetCustomAttributes(true))
.OfType<SwaggerOperationAttribute>()
.Select(a => a.OperationId)
.FirstOrDefault();
}
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class SwaggerOperationAttribute : Attribute
{
public SwaggerOperationAttribute(string operationId)
{
OperationId = operationId;
}
public string OperationId { get; }
}
// Startup.cs
services.AddSwaggerGen(c =>
{
...
c.OperationFilter<SwaggerOperationNameFilter>();
};
[HttpGet("{id:int}")]
[SwaggerOperation("GetById")]
public async Task<IActionResult> Get(int id)
{
...
}
But it still seems to me that I've reinvented the wheel.