How add to multiple collection using swagger .Net Core

37 Views Asked by At

I am working on an application where I need to add multiple collections for web and mobile. But the swagger is empty. Here is my code

namespace RIOnlySelfCareService.Controllers
{
    [Route("api/web/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly IAccountService accountService;
        private readonly IMenuService _menuService;

        public AccountController(IAccountService accountService, IMenuService menuService)
        {
            this.accountService = accountService;
            _menuService = menuService;
        }

        [HttpPost("getMenus")]
        public async Task<IActionResult> GetMenusAsync()
        {
            return Ok(await _menuService.GetMenusAsync());
        }
    }
}

namespace RIOnlySelfCareService.Controllers.MobileControllers
{
    [Route("api/mobile/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly IAccountService accountService;
        private readonly IMenuService _menuService;

        public AccountController(IAccountService accountService, IMenuService menuService)
        {
            this.accountService = accountService;
            _menuService = menuService;
        }

        [HttpPost("getMenus")]
        public async Task<IActionResult> GetMenusAsync()
        {
            return Ok(await _menuService.GetMenusAsync());
        }
    }
}

Program.cs

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("web", new OpenApiInfo
    {
        Title = "Self Care Web API",
        Version = "v1"
    });
    c.SwaggerDoc("mobile", new OpenApiInfo
    {
        Title = "Self Care Mobile API",
        Version = "v1"
    });

    c.DocInclusionPredicate((docName, apiDesc) =>
    {
        // Check if the controller's route contains the specified prefix
        if (apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
        {
            var controllerAttribute = methodInfo.DeclaringType?.GetCustomAttributes(true)
                .OfType<RouteAttribute>()
                .FirstOrDefault();

            if (controllerAttribute != null)
            {
                var routePrefix = controllerAttribute.Template.ToLower();

                // Group controllers based on route prefixes
                if (docName == "web" && routePrefix.StartsWith("api/web"))
                    return true;

                if (docName == "mobile" && routePrefix.StartsWith("api/mobile"))
                    return true;
            }
        }

        return false;
    });
 }

if (!app.Environment.IsProduction())
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        // Render Swagger UI for web controllers
        options.SwaggerEndpoint("/swagger/web/swagger.json", "Self Care Web API");
        // Render Swagger UI for mobile controllers
        options.SwaggerEndpoint("/swagger/mobile/swagger.json", "Self Care Mobile API");
    });
}
1

There are 1 best solutions below

0
Jason Pan On

Split this line of your code methodInfo.DeclaringType?.GetCustomAttributes(true).OfType<RouteAttribute>().FirstOrDefault(); as follows:

var CustomAttributes = methodInfo.DeclaringType?.GetCustomAttributes(true);

var controllerAttributeOfType = CustomAttributes.OfType<RouteAttribute>();

I found that after using OfType,the controllerAttributeOfType has always been null, and the code under the if (controllerAttribute != null) condition cannot be executed.

Then I found there are two namespaces for `RouteAttribute`, one is `Microsoft.AspNetCore.Mvc`, another one is `Microsoft.AspNetCore.Components`.

So the soultion is, we need to use Microsoft.AspNetCore.Mvc.RouteAttribute, then the issue will be fixed.

Here is my test code and test result:

            c.DocInclusionPredicate((docName, apiDesc) =>
            {
                var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
                if (apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
                {
                    // for testing, you can delete these 2 line later
                    var CustomAttributes = methodInfo.DeclaringType?.GetCustomAttributes(true);

                    var controllerAttributeOfType = CustomAttributes.OfType<Microsoft.AspNetCore.Mvc.RouteAttribute>();


                    var controllerAttribute = methodInfo.DeclaringType?.GetCustomAttributes(true)
                        .OfType<Microsoft.AspNetCore.Mvc.RouteAttribute>()
                        .FirstOrDefault();

                    if (controllerAttribute != null)
                    {
                        var routePrefix = controllerAttribute.Template.ToLower();
                        var include = (docName == "web" && routePrefix.StartsWith("api/web")) ||
                                      (docName == "mobile" && routePrefix.StartsWith("api/mobile"));

                        logger.LogInformation($"API {methodInfo.DeclaringType?.Name}.{methodInfo.Name} ({routePrefix}) inclusion for {docName}: {include}");
                        return include;
                    }
                }

enter image description here

enter image description here