How to resolve Swagger error "Conflicting method/path combination" , when you are using Gerneric base Controller and inherit it to many controllers

Viewed 1206

I have created a generic base API controller and inherited that in to multiple other controllers.
I think Swagger always need unique and not so ambiguous route name etc.
Now because of generic controller implementation, I am getting error like:

SwaggerGeneratorException: Conflicting method/path combination :Actions require a unique method/path combination for Swagger/OpenAPI 3.0. : Use ConflictingActionsResolver as a workaround"

Is there any way to resolve it?

[ApiController]
[Route("api/odata/[controller]/[action]")]
[Consumes("application/json")]
public class BaseController<T> : Controller where T : XPBaseObject
{
    private Storage<T> _storage;

    public BaseController(Storage<T> storage)
    {
        _storage = storage;
    }

    [Route("Get")]
    [HttpGet]
    
    public IEnumerable<T> Get()
    {
        return _storage.GetAll();
    }
}

public class EmployeeController : BaseController<Employee>
{
    public EmployeeController(Storage<Employee> storage) : base(storage)
    {
    }
}//Employee controller



public class CompanyController : BaseController<Company>
{
    public CompanyController(Storage<Company> storage) : base(storage)
    {
    }
}//Company controller

//Startup.cs

public class Startup
{
    public IConfiguration Configuration { get; }
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    //  This method gets called by the runtime.Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers()
        .AddOData(opt => opt.Count().Filter().Expand().Select().OrderBy().SetMaxTop(100));

        services.AddControllers().AddOData(opt => opt.AddRouteComponents("api/odata", SingletonEdmModel.GetEdmModel()));

        services.AddControllers(mvcOptions =>
        {
            mvcOptions.EnableEndpointRouting = false;
        });

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
             .AddCookie();
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<XpoDataStoreProviderService>();
        services.AddSingleton(Configuration);
        services.AddSingleton(typeof(Storage<>));
     
        services.AddHttpContextAccessor();
        services.AddScoped<SecurityProvider>();
        services.AddRouting();
        services.AddScoped((serviceProvider) => {
            AuthenticationMixed authentication = new AuthenticationMixed();
            authentication.LogonParametersType = typeof(AuthenticationStandardLogonParameters);
            authentication.AddAuthenticationStandardProvider(typeof(PermissionPolicyUser));
            authentication.AddIdentityAuthenticationProvider(typeof(PermissionPolicyUser));
            SecurityStrategyComplex security = new SecurityStrategyComplex(typeof(PermissionPolicyUser), typeof(PermissionPolicyRole), authentication);
            return security;
        });

        #region Swagger

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "PAM_System.ODataWebService", Version = "v1" });

            //Do you need to add accesstoken to URL when you need control the request in swagger?
            //c.OperationFilter<AddAuthTokenHeaderParameter>();
        });

        // Customize the Swagger generator here
        services.ConfigureSwaggerGen(options =>
        {
            // Use fully qualified schema object names to ensure uniqueness
            options.CustomSchemaIds(configuration => configuration.FullName);
        });
        #endregion

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "PAM_System.ODataWebService v1"); });
        }
        else
        {
            app.UseHsts();
        }

        app.UseAuthentication();
        app.UseHttpsRedirection();
        app.UseDefaultFiles();
        app.UseStaticFiles();


        app.UseODataQueryRequest();
        app.UseODataBatching();

        app.UseRouting();
        app.UseCors();
        app.UseCookiePolicy();
        app.UseAuthorization();


        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "PAM_System.ODataWebService v1");
            c.RoutePrefix = "PAM_System.ODataWebService/swagger"; //set Root node access
            
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();

        });


        app.UseDemoData(Configuration.GetConnectionString("XafApplication"));

    }
}

Also I tried following code in my startup.cs, then I am able to see my Controller map into swagger but Action gets no response it’s just gets stuck there for long time

services.AddSwaggerGen(c =>
        {
            c.ResolveConflictingActions(apiDescriptions =>
            {
                var descriptions = apiDescriptions as ApiDescription[] ?? apiDescriptions.ToArray();
                var first = descriptions.First(); // build relative to the 1st method
                var parameters = descriptions.SelectMany(d => d.ParameterDescriptions).ToList();

                first.ParameterDescriptions.Clear();
                // add parameters and make them optional
                foreach (var parameter in parameters)
                    if (first.ParameterDescriptions.All(x => x.Name != parameter.Name))
                    {
                        first.ParameterDescriptions.Add(new ApiParameterDescription
                        {
                            ModelMetadata = parameter.ModelMetadata,
                            Name = parameter.Name,
                            ParameterDescriptor = parameter.ParameterDescriptor,
                            Source = parameter.Source,
                            IsRequired = false,
                            DefaultValue = null
                        });
                    }
                return first;
            });
        });
0 Answers
Related