如何在 ASP.NET CORE 3.0 中配置路由以使用带有 [FromQuery] 参数的重载 [HttpGet] 方法?

How to configure routing in ASP.NET CORE 3.0 to use overload [HttpGet] method with [FromQuery] parameters?

抱歉标题,我不擅长,如果你知道更好的标题来描述问题的内容,请告诉我。

所以我有两种方法,第一种是获取所有列表项,第二种也是获取所有列表项,但是,第二种方法有一个查询参数,我用它来过滤器,第二种方法也 returns 与第一种方法不同 object。因为我有 2 个 Http get 方法去同一条路线,当我调用其中一个方法时,我得到:

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: .....

如何在不合并这两个方法或不使用可选参数或改变一个方法的路径的情况下解决这个问题?如果可以的话??

示例代码:

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<ICollection<Data>>> GetAll()
{
    return Ok(await Service.GetAll());
}

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<Data2>> GetAll([FromQuery]int parameter)
{
    return Ok(await Service.GetAll2(parameter));
}

在配置方法中我有:

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();

app.UseAuthorization();

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

编辑:按照评论的建议尝试在这样的配置中使用操作...

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("default", "{controller}/{action}/{id?}");
});

它不起作用,因为当我向其发出获取请求时调用了错误的方法, 例如,第一个 getall 方法:api/resources/getall 下面的方法被触发而不是导致错误,因为 getall 不是一个 int...

// GET: api/Resources/5
[HttpGet("{id}")]
public async Task<ActionResult<Data>> GetById(int id)
{
    return Ok(await Service.GetById(id));
}

重现示例 >> https://drive.google.com/open?id=15EB1_kK-c_qyhRS0QvVlKnhuUbFjyN12


现在操作正常,必须更改控制器中的属性路由...

[Route("api/[controller]/[action]")]
[ApiController]
public class ResourcesController : ControllerBase
{
    // GET: api/Resources/GetAll
    [HttpGet]
    public ActionResult<ICollection<string>> GetAll()
    {
        return Ok(new List<string>() { "foo", "bar" });
    }

    // GET: api/Resources/GetAll2?parameter="bar"
    [HttpGet]
    public ActionResult<string> GetAll2([FromQuery]string parameter)
    {
        return Ok(parameter);
    }

    // GET: api/Resources/GetById/5
    [HttpGet("{id}")]
    public ActionResult<int> GetById(int id)
    {
        return Ok(id);
    }
}

虽然如果没有不同的路径就不可能实现这一点,我将只更改一个方法的路径而不是在控制器中使用动作,并且在调用时必须在路径中添加动作名称方法。

更新 1:几周后我遇到的其他可能有用的东西(未测试)是使用路由约束,如 this video.

中所示

更新 2:差不多一年后,我决定查找查询参数约束, 我在 Whosebug 上遇到了 this question,答案是不可能的,尽管这个问题已经很老了所以...

How do I solve this without merging the 2 methods or making use of optional parameters, or changing the path of one method? if possible??

如果你想让它在不合并这两个动作或在路由中指定动作名称的情况下工作,你可以尝试使用 Http[Verb] attributes 让你的第二个动作接受来自路由数据的参数,如下所示.

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<ICollection<Data>>> GetAll()
{
    return Ok(await Service.GetAll());
}


// GET: api/Resources/1
[HttpGet("{parameter:int}")]
public async Task<ActionResult<Data2>> GetAll([FromRoute]int parameter)
{
    return Ok(await Service.GetAll2(parameter));
}

此外,在我看来,合并这两个操作并使用可选参数会更好。我想知道什么场景不需要使用这种方法来实现需求。

[HttpGet("{parameter:int?}")]
public async Task<IActionResult> GetAll([FromQuery]int parameter)
{
    if (parameter == 0)
    {
        return Ok(await Service.GetAll());
    }
    else
    {
        return Ok(await Service.GetAll2(parameter));
    }
}

作为参考,我创建了一个新的 web api asp.net core 3 项目。

另外假设您在 Startup.cs. endpoints.MapDefaultControllerRoute();

上注册了默认路由

添加

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

在您的控制器启动时会覆盖您的启动,因此您不必担心其他控制器。

Also you cannot achieve this with the Id being optional parameter. You would get ambiguity. Since GetAll() and GetAll(int parameter) are precisely the same, since we have declared the parameter as optional. This is why you get the error.

using Microsoft.AspNetCore.Mvc;

namespace WebApiTest.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ResourceController : ControllerBase
    {

        [HttpGet]
        //api/Resource/GetAll
        public IActionResult GetAll()
        {
            return Content("I got nth");
        }

        //GET: //api/Resource/GetAll/2
        [HttpGet("{parameter}")]
        public IActionResult GetAll(int parameter)
        {
            return Ok($"Parameter {parameter}");
        }

    }
}

另请注意,在第二个 GetAll() 中,我在 HttpGet 中添加了参数。

这只是为了更新路由引擎,该路由将有一个参数,因为在我的文件顶部的通用级别,我正在注册直到操作。

要获得更多参数,您可以这样做。 [HttpGet({parameter}/{resourceId})]

那么您的路线将类似于 api/Resource/GetAll/2/4