操作需要在Swagger中具有唯一的方法/路径组合

63

我在同一个控制器中有两个HTTP GET方法,导致出现以下错误:

DPK.HostApi.Controllers.DataStoreController.GetByIdAsync (DPK.HostApi)和DPK.HostApi.Controllers.DataStoreController.GetAllAsync (DPK.HostApi)都使用了HTTP方法"GET"和路径"api/DataStore"。Swagger 2.0要求操作需要具有唯一的方法/路径组合。

我的控制器:

[Route("api/[controller]")]
[ApiController]
public class DataStoreController : ApiControllerBase
{
    private readonly IDataStoreService _dataStoreService;

    public DataStoreController(IDataStoreService dataStoreService)
    {
        _dataStoreService = dataStoreService;
    }


    [HttpPost]
    public async Task<IActionResult> PostAsync([FromBody] DataStoreCommand dataStoreCommand)
    {
        try
        {
            if (ModelState.IsValid)
            {
                await _dataStoreService.PostAsync(dataStoreCommand);
                return Ok();
            }

            var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
            return ValidationProblem();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }


    [HttpPut]
    public async Task<IActionResult> PutAsync([FromBody] DataStoreCommand dataStoreCommand)
    {
        try
        {
            if (ModelState.IsValid)
            {
                await _dataStoreService.PutAsync(dataStoreCommand);
                return Ok();
            }

            var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
            return ValidationProblem();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }


    [HttpDelete]
    public async Task<IActionResult> DeleteAsync(int id)
    {
        try
        {
            if (ModelState.IsValid)
            {
                var item = await _dataStoreService.GetByIdAsync(id);
                await _dataStoreService.DeleteAsync(item);
                return Ok();
            }

            var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
            return ValidationProblem();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }


    [HttpGet]
    public async Task<DataStoreQuery> GetByIdAsync(int id)
    {
        try
        {
            return await _dataStoreService.GetByIdAsync(id);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }





    [HttpGet]
    public async Task<IEnumerable<DataStoreQuery>> GetAllAsync(string instanceName, string dbname, string userName, string userPass, bool isActive, DateTime? startCreatedDate, DateTime? endCreatedDate, DateTime? startModifiedDate, DateTime? endModifiedDate)
    {
        object[] parameters = { instanceName, dbname, userName, userPass, isActive, startCreatedDate, endCreatedDate, startModifiedDate,  endModifiedDate};
        var parameterName = "@instanceName , @dbname , @userName , @userPass , @isActive , @startCreatedDate , @endCreatedDate , @startModifiedDate , @endModifiedDate";
        try
        {
            return await _dataStoreService.ExecWithStoreProcedure(parameterName, parameters);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }




}

我的创业公司:

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

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info
            {
                Version = "v1",
                Title = " ",
                Description = " ",
                TermsOfService = "None",
                Contact = new Contact() { Name = " ", Email = " ", Url = " " }
            });
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();


        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
    }
}
9个回答

73

我把控制器路由更改为以下内容:

[Route("api/[controller]/[action]")]

或者您也可以定义一个显式路由来处理该操作:

[Route("GetById")]

由于某些原因,当我使用[Route]时,在文档中我无法获得api/v1/[controller]/myroute,而只能获得/myroute,而所有其他HTTP动词都具有完整的API路径。第一个解决方案是合理的,因为它似乎将方法名称作为终点引入。 - user1574598
谢谢。你救了我的命。 - Fk Bey
只需简单地使用 '[Route("api/[controller]/[action]")]' 就可以完美地工作。 - undefined

60

您可以按照以下步骤解决:

services.AddSwaggerGen (c =>
  {
    other configs;
    c.ResolveConflictingActions (apiDescriptions => apiDescriptions.First ());
  });
//in the Startup.cs class in the ConfigureServices method

或者你可以使用路由来区分你的方法,例如:

[HttpGet("~/getsomething")]
[HttpGet("~/getothersomething")]

24
第一种解决方案意味着只有第一个操作会在 Swagger 中记录。一般来说,您希望避免未记录的端点... - Neurion

12

你需要将id映射到HttpGet中。

[HttpGet("{id}")]
public async Task<DataStoreQuery> GetByIdAsync(int id)
{
    try
    {
        return await _dataStoreService.GetByIdAsync(id);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

如果您在未提供模板的情况下指定了HttpGet,则Swashbuckle会尝试为它们都使用默认映射。因此会出现冲突。


6
如果方法中有“Name”,那么它也会抛出此错误。为了修复它,
从以下进行更改:
[HttpGet(Name = "GetWeatherForecast")]
[HttpGet(Name = "GetWeatherForecastById")]

[HttpGet("GetWeatherForecast")]
[HttpGet("GetWeatherForecastById")]

5

您还可以将端点相同的方法合并为一个带有可选参数的方法。以下是在 .NET Core 5 项目中测试实现的示例:

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;
    });
});

4
如果方法名相同,则需要更改请求方法并添加参数。 我将请求方法更改为以下内容:
[HttpGet]
    public string products()
    {
        // add other code
        // ex. (return "products()";)
    }


[HttpGet("{id}")]
    public string products(int id)
    {
        // add other code
        // ex. (return "products(int id)";)
    }

1
这是我指定方法名称唯一路由的方式。
[HttpGet("~/GetWeatherForecast")]

保持在方法之上

[HttpGet("~/GetWeatherForecast")]
public int Get()
{
   return Random.Next(5)
}

[HttpPost("~/InsertAddition")]
public int InsertAddition(int num1, int num2)
{
  return num1 + num2;
}

0

尝试同时添加Route和HttpGet。

    [HttpGet]
    [Route(~/GetByIdAsync/{id})]
    public async Task<DataStoreQuery> GetByIdAsync(int id)

    [HttpGet]
    [Route(~/GetAllAsync)]
    public async Task<IEnumerable<DataStoreQuery>> GetAllAsync(string instanceName, string dbname, string userName, string userPass, bool isActive, DateTime? startCreatedDate, DateTime? endCreatedDate, DateTime? startModifiedDate, DateTime? endModifiedDate)

0
你也可以忽略过时的方法。
 services.AddSwaggerGen(swaggerGenOptions =>
 {
     swaggerGenOptions.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
     swaggerGenOptions.IgnoreObsoleteActions();
     swaggerGenOptions.IgnoreObsoleteProperties();
     swaggerGenOptions.CustomSchemaIds(type => type.FullName);
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接