Open Closed

If BlogPostPublicAppService is overridden, Swagger returns an error #10889


User avatar
0
lszabados@consult2000.hu created

Hello,

Example solution: Version 10.5.0 Layered + Blazor Server + EF Core SQL Server + Multi-Tenancy + Public Web + CMS Kit + Tiered License: Team edition

Based on the documentation “Customizing the Application Modules: Overriding Services,” I am trying to override certain methods of the BlogPostPublicAppService.

The override works, but Swagger throws an error.

In the example below, I’m not overriding anything—I’m just defining my own implementation—and I’m already getting the error. This is a completely clean, new solution,

Everything works fine when overriding the MediaDescriptorAppService; I’ve only encountered this issue when overriding the BlogPostPublicAppService.

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBlogPostPublicAppService), typeof(BlogPostPublicAppService), typeof(VoxoBlogPostPublicAppService))]
public class VoxoBlogPostPublicAppService : BlogPostPublicAppService
{

    public VoxoBlogPostPublicAppService(IBlogRepository blogRepository, IBlogPostRepository blogPostRepository, ITagRepository tagRepository, BlogPostManager blogPostManager)
        : base(blogRepository, blogPostRepository, tagRepository, blogPostManager)
    {

    }
}

Error: 2026. 09. 20. 17:16:31 [Error] Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Conflicting method/path combination "GET api/app/voxo-blog-post-public" for actions - ReplaceTest2.Blog.VoxoBlogPostPublicAppService.GetAsync (ReplaceTest2.Application), ReplaceTest2.Blog.VoxoBlogPostPublicAppService.GetListAsync (ReplaceTest2.Application). Actions require a unique method/path combination for Swagger/OpenAPI 2.0 and 3.0. Use ConflictingActionsResolver as a workaround or provide your own implementation of PathGroupSelector. at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.PrepareGenerateOperation(IGrouping`2 group)

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

4 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • BlogPostPublicAppService is exposed as an HTTP API via Auto API Controllers. When you add your derived class in the Application layer, ABP will treat it as a new application service and (by convention) it will also be turned into an API controller.
    • With your attributes you also replace the original service in DI, but you still end up with two actions that Swagger sees under the same controller/route group, so Swashbuckle detects a conflict.

    In your specific case, both of these methods end up being mapped to the same conventional route:

    • GetAsync(...)GET /api/app/voxo-blog-post-public
    • GetListAsync(...)GET /api/app/voxo-blog-post-public

    Swashbuckle then throws:

    Conflicting method/path combination "GET api/app/voxo-blog-post-public" …

    This happens because Auto API Controller conventional routing requires unique GET routes, and ABP’s conventional routing is based on method names/signatures. If the method parameters don’t let ASP.NET Core distinguish the templates (e.g., no {id} segment ends up in the template for one of them), you’ll get exactly this kind of Swagger collision.

    Fix (recommended): don’t expose your replacement type as an API controller

    Keep the replacement only in DI, and ensure only one controller is generated.

    Use only the interface/base service exposure, and do not expose the concrete type itself:

    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IBlogPostPublicAppService))]
    public class VoxoBlogPostPublicAppService : BlogPostPublicAppService
    {
        public VoxoBlogPostPublicAppService(
            IBlogRepository blogRepository,
            IBlogPostRepository blogPostRepository,
            ITagRepository tagRepository,
            BlogPostManager blogPostManager)
            : base(blogRepository, blogPostRepository, tagRepository, blogPostManager)
        {
        }
    }
    

    Notes:

    • Remove typeof(BlogPostPublicAppService) and typeof(VoxoBlogPostPublicAppService) from [ExposeServices].
    • This way ABP still resolves IBlogPostPublicAppService to your class, but the framework won’t treat your class as an additional HTTP endpoint “service type” to generate routes for.

    Alternative fix: explicitly set routes (if you must expose the class)

    If you really want the class to be treated as a separate API controller, you must ensure GetAsync and GetListAsync do not map to the same GET path by explicitly adding [HttpGet] / [Route] attributes (or changing method names). But in an override/replacement scenario, that’s usually not what you want.


    Links (verified):

    • https://abp.io/docs/10.5/framework/architecture/modularity/extending/customizing-application-modules-overriding-services
    • https://abp.io/docs/10.5/framework/api-development/auto-controllers

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lszabados@consult2000.hu created

    Using the [ExposeServices(typeof(IBlogPostPublicAppService))] setting yields the same result.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • This specific Swagger error means ASP.NET Core has two GET actions that end up with the exact same route template under ABP’s Auto API Controllers conventions.
    • In your case, after replacing BlogPostPublicAppService, ABP’s conventional routing ends up mapping both:
      • GetAsync(...) and
      • GetListAsync(...) to the same path: GET /api/app/voxo-blog-post-public

    That can happen if GetAsync is not considered to have an id route parameter by the conventional route builder (e.g., its parameter name/type doesn’t match what the convention expects), so ABP doesn’t add /{id} and both methods collapse to the same route.

    Solution (definitive): explicitly define HTTP routes for the conflicting methods in your replacement

    Override the methods you want (even if you keep the base logic) and add explicit ASP.NET Core route attributes so they can’t collapse to the same path.

    Example pattern:

    using Microsoft.AspNetCore.Mvc;
    
    public class VoxoBlogPostPublicAppService : BlogPostPublicAppService
    {
        public VoxoBlogPostPublicAppService(
            IBlogRepository blogRepository,
            IBlogPostRepository blogPostRepository,
            ITagRepository tagRepository,
            BlogPostManager blogPostManager)
            : base(blogRepository, blogPostRepository, tagRepository, blogPostManager)
        {
        }
    
        [HttpGet]
        [Route("api/app/voxo-blog-post-public/{id}")]
        public override Task<BlogPostPublicDto> GetAsync(Guid id)
        {
            return base.GetAsync(id);
        }
    
        [HttpGet]
        [Route("api/app/voxo-blog-post-public")]
        public override Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(BlogPostPublicGetListInput input)
        {
            return base.GetListAsync(input);
        }
    }
    

    Key points:

    • Force GetAsync to be .../{id} and GetListAsync to be the collection route.
    • This avoids any ambiguity/bug/edge-case in conventional route calculation after replacement.

    Why [ExposeServices(typeof(IBlogPostPublicAppService))] didn’t change it

    Because the problem is not “two controllers exist”; it’s “two actions resolve to the same HTTP method + path” for the generated controller of the service type that ends up exposed. Replacing DI alone doesn’t guarantee the auto-controller route templates remain unique after conventions are applied.

    Sources (validated)

    • https://abp.io/docs/10.5/framework/api-development/auto-controllers

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    lszabados@consult2000.hu created

    Yes, that turned out to be the solution.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.