如何在Swagger/Swashbuckle中为C# API文档添加第三层分组?
Got it, let's fix that flat grouping issue you're dealing with! Swashbuckle and Swagger UI absolutely support nested hierarchical groups—you just need to tweak how you define your controller groups and adjust a few UI settings. Here's a step-by-step breakdown:
1. Define Hierarchical Group Names for Controllers
The key is to use slash-separated group names in your controller's [ApiExplorerSettings] attribute. This tells Swagger UI to render them as nested menus.
For example:
// Integration Settings Controller [ApiController] [Route("api/access-integration/integration-settings")] [ApiExplorerSettings(GroupName = "Access Integration/Integration Settings")] public class IntegrationSettingsController : ControllerBase { // Your API actions here } // Sync Users Controller [ApiController] [Route("api/access-integration/sync-users")] [ApiExplorerSettings(GroupName = "Access Integration/Sync Users")] public class SyncUsersController : ControllerBase { // Your API actions here } // Sync Doors Controller [ApiController] [Route("api/access-integration/sync-doors")] [ApiExplorerSettings(GroupName = "Access Integration/Sync Doors")] public class SyncDoorsController : ControllerBase { // Your API actions here }
You can even go deeper with nested levels if needed—like Access Integration/Sync/Sync Users—Swagger UI will automatically render multi-level nested menus.
2. Configure Swagger UI to Support Hierarchical Display
Next, update your Swagger UI configuration to enable deep linking and ensure the nested groups render correctly. In your Program.cs (or Startup.cs for older .NET versions):
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API V1"); c.EnableDeepLinking(); // Critical for nested group navigation c.DisplayOperationId(); // Optional, but helps with debugging // Swagger UI will automatically handle slash-separated group names as nested menus });
3. Optional: Auto-Generate Hierarchical Groups (Avoid Manual Attribute Work)
If you don't want to manually add [ApiExplorerSettings] to every controller, you can create a custom IDocumentFilter to auto-generate group names based on your controller routes or namespaces.
Here's an example filter that derives groups from the first two segments of your route:
public class HierarchicalGroupFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { foreach (var apiDesc in context.ApiDescriptions) { // Split the route template and extract relevant segments var routeSegments = apiDesc.Route.RouteTemplate.Split('/') .Where(segment => !segment.StartsWith("{") && !string.IsNullOrWhiteSpace(segment)); if (routeSegments.Take(2).Any()) { // Create a slash-separated group name from the first two route segments apiDesc.GroupName = string.Join("/", routeSegments.Take(2)); } } // Clean up duplicate tags in the Swagger document swaggerDoc.Tags = swaggerDoc.Tags .GroupBy(tag => tag.Name) .Select(group => group.First()) .OrderBy(tag => tag.Name) .ToList(); } }
Register the filter in your Swagger setup:
builder.Services.AddSwaggerGen(c => { c.DocumentFilter<HierarchicalGroupFilter>(); // Your other Swagger config (like XML comments, etc.) });
Result
Once you implement this, your Swagger UI will display a single Access Integration parent group. Clicking it will expand to show all your child groups (Integration Settings, Sync Users, Sync Doors, etc.), and each child group will contain its respective API operations. You can keep adding deeper nested groups as your API grows—Swagger UI will handle the folding/unfolding automatically.
内容的提问来源于stack exchange,提问作者Casey Crookston

