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

Posted

技术标签:

【中文标题】如何在 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? 【发布时间】:2019-12-10 13:41:55 【问题描述】:

对不起标题,我不擅长它们,如果您知道更好的标题来描述问题的内容,请告诉我。

所以我有两个方法,第一个是获取所有列表项,第二个也是获取所有列表项,但是,第二个方法有一个查询参数,我用来过滤,并且第二种方法也返回与第一种方法不同的对象。由于我有 2 个 Http get 方法去同一条路线,当我调用我得到的方法之一时:

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: 请求匹配多个端点。匹配:.....

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

示例代码:

// 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();
);

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

app.UseEndpoints(endpoints =>

    endpoints.MapControllerRoute("default", "controller/action/id?");
);

它不起作用,因为当我发出 get 请求时调用了错误的方法, 比如第一个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));


repro 示例 >> 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:将近一年后,我决定查找查询参数约束, 我在***上遇到了this question,答案是不可能的,虽然这个问题很老所以......

【问题讨论】:

你的问题在于路由而不是方法。你能提供你的web api配置吗?默认情况下,它有这个 api/controller/id,这可能是非常有问题的。因为如果你的 web api 中有两个方法具有相同的参数控制器,你会得到歧义,换句话说,你的错误, 看看这个问题的答案-> ***.com/questions/59157364/… @panoskarajohn 所以我必须采取行动?没有别的办法吗? 很遗憾没有。您对路线越具体。你得到的歧义越少。由于 api 忽略了动作,因此两种方法之间的歧义并不罕见。你必须重新考虑你的 web api 设计。您可以参考文档了解更多信息 -> docs.microsoft.com/en-us/aspnet/core/tutorials/… @panoskarajohn 知道如何使这些操作在 .NET Core 3.0 中工作?我试过: app.UseEndpoints(endpoints => endpoints.MapControllerRoute("default", "controller/action/id?"); );但没有用。 【参考方案1】:

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

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

上注册了默认路由

添加

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

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

您也无法通过 Id 作为可选参数来实现这一点。 你会变得模棱两可。由于 GetAll() 和 GetAll(int parameter) 完全相同,因为我们已将参数声明为可选。 这就是你得到错误的原因。

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

【讨论】:

好的,我更新了 repro 示例 >> drive.google.com/open?id=15EB1_kK-c_qyhRS0QvVlKnhuUbFjyN12 控制器中的属性路由似乎是我的问题,现在可以工作了,谢谢。【参考方案2】:

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

如果您想在不合并这两个动作或在路由中指定动作名称的情况下使其工作,您可以尝试使用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));
    

【讨论】:

是的,但是,我得到的参数变量是从查询中得到的,不是资源的 id,所以把它作为路径变量对路径没有意义,合并是我真的不想做的事情。 我正在尝试通过使用问题下方 cmets 建议的操作来使其工作,但我不知道如何在启动时为它进行路由配置,对于 netcore 3.0 api

以上是关于如何在 ASP.NET CORE 3.0 中配置路由以使用带有 [FromQuery] 参数的重载 [HttpGet] 方法?的主要内容,如果未能解决你的问题,请参考以下文章

asp.net core 3.0 MVC JSON 全局配置

在Asp.Net Core 3.0中如何使用 Newtonsoft.Json 库序列化数据

在 Razor (chtml) 中渲染动态视图,如何在 asp.net core 3.0 中将 FileProvider 添加到 razor?

如何在 ASP NET CORE 3.0 中获取当前登录的用户 ID?

从 ASP.NET Core 2.2 升级到 3.0

这是如何使用 Entity Framework Core 和 ASP.NET Core MVC 2.2+ 和 3.0 创建数据传输对象 (DTO)