30

I have controller like

public class UserController : ApiController
{
  [Route("api/user")]
  IHttpActionResult GetUser() { ... }
}

public class ResumeController : ApiController
{
  [Route("api/user/resumes")]
  IHttpActionResult GetResumes() { ... }
}

Which on swagger generates output like enter image description here

Is there a way (besides overriding default implementation by rolling out your own ISwaggerProvider or merging two controllers into one) to enforce the group name ? Something like

public class UserController : ApiController
{
  [Route("api/user")]
  [MagicalAttributeName(Group="User")]
  IHttpActionResult GetUser() { ... }
}

public class ResumeController : ApiController
{
  [Route("api/user/resumes")]
  [MagicalAttributeName(Group="User")]
  IHttpActionResult GetResumes() { ... }
}
Mark Mucha
  • 1,560
  • 2
  • 12
  • 18
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • 4
    I wish I could upvote this twice. Once because it's the exact question i was looking for, and again for the use of `MagicalAttributeName`. – Casey Crookston Mar 06 '18 at 16:31

4 Answers4

35

You could also use SwaggerOperationAttribute:

public class UserController : ApiController
{
    [Route("api/user")]
    [SwaggerOperation(Tags = new[] { "User" })]
    IHttpActionResult GetUser() { ... }
}

public class ResumeController : ApiController
{
    [Route("api/user/resumes")]
    [SwaggerOperation(Tags = new[] { "User" })]
    IHttpActionResult GetResumes() { ... }
}
Andriy Tolstoy
  • 5,690
  • 2
  • 31
  • 30
13

There is a way - although there is no magic attribute - you can change default rules of grouping in swagger startup configuration in order to introduce your very own custom attribute.

GlobalConfiguration.Configuration 
 .EnableSwagger(c => {
   c.GroupActionsBy(apiDesc => apiDesc
     .GetControllerAndActionAttributes<MethodGroupAttribute>().Any() ?
        apiDesc.GetControllerAndActionAttributes<MethodGroupAttribute()
        .First().GroupName :
        apiDesc.ActionDescriptor.ControllerDescriptor.ControllerName);
 });


/// <summary>
/// Forces method to be displayed within specified group, regardless of controller
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MethodGroupAttribute : Attribute
{
    /// <summary>
    /// Group name
    /// </summary>
    public string GroupName { get; private set; }

    /// <summary>
    /// ctor
    /// </summary>
    /// <param name="groupName"></param>
    public MethodGroupAttribute(string groupName)
    {
        if (string.IsNullOrEmpty(groupName))
        {
            throw new ArgumentNullException("groupName");
        }
        GroupName = groupName;
    }
}

Usage:

[Route("api/user")]
[MethodGroup("User")]
IHttpActionResult GetUser() { ... }
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • thanks. i was able to adapt this to work at the controller/class level. – Dennis Aug 26 '16 at 05:45
  • 1
    I can't get this to work. I get: `ApiDescription does not contain a definition for GetControllerAndActionAttributes` – Casey Crookston Mar 06 '18 at 17:39
  • @CaseyCrookston - see https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/Swagger/ApiDescriptionExtensions.cs (i.e are you missing using Swashbuckle.Swagger ? ) – Ondrej Svejdar Mar 06 '18 at 18:15
  • @Dennis It sounds like what you did is exactly what I am trying to do here: https://stackoverflow.com/questions/54222584/how-to-change-controllers-name-in-swagger-ui. – markf78 Jan 25 '19 at 18:01
  • 1
    Your missing a closing > in your code, it caused an error when I copied and pasted into Visual Studio, this worked however, c.GroupActionsBy(apiDesc => apiDesc.GetControllerAndActionAttributes().Any() ? apiDesc.GetControllerAndActionAttributes().First().GroupName : apiDesc.ActionDescriptor.ControllerDescriptor.ControllerName); – TroySteven Jul 11 '19 at 15:15
2

I know it is very late but leaving the answer thinking it would be useful. You can use the ApiExplorerSettings, this is your magic attribute.
Something like this...

public class UserController : ApiController
{
  [Route("api/user")]
  [ApiExplorerSettings(GroupName="User")]
  IHttpActionResult GetUser() { ... }
}

public class ResumeController : ApiController
{
  [Route("api/user/resumes")]
  [ApiExplorerSettings(GroupName="User")]
  IHttpActionResult GetResumes() { ... }
}
Ε Г И І И О
  • 11,199
  • 1
  • 48
  • 63
user213932
  • 31
  • 1
  • 6
0

If you happen to be developing an Azure Function App while useing OpenApi annotations from Microsoft.Azure.WebJobs.Extensions.OpenApi, the magic attribute is the 2nd (tags) parameter in OpenApiOperation.

public class ResumeFunction
{
  [FunctionName("GetUser")]
  [OpenApiOperation(operationId: "GetUser", "User")]
  public async Task<IActionResult> Run() { ... }
}
Ε Г И І И О
  • 11,199
  • 1
  • 48
  • 63