【问题标题】:ASP.NET Core Web API : route by query parameterASP.NET Core Web API:按查询参数路由
【发布时间】:2022-01-08 12:17:55
【问题描述】:

我的 Java/Spring 背景很重,并试图将一些知识转移到 ASP.NET Core 6。

在 Spring 中,在 RestController 上,我能够根据查询参数的存在来路由请求。

因此,带有 uri:/students?firstName=KevinHttpRequest 可以路由到与带有 uri:/studentsHttpRequest 不同的控制器方法。

在 ASP.NET Core 6 中,在完成一些示例并阅读 Web API 文档后,我无法确定是否可以实现等效。

这是我想要实现的,这是否可以使用两种方法和路由配置来识别根据查询参数调用哪个控制器方法?

 [ApiController]
 [Route("Students")]
 public class StudentHomeProfileController : ControllerBase
 {
    [HttpGet] //Route here when no parameters provided
    public async Task<ActionResult<IEnumerable<Student>>> GetStudentAsync()
    {
        /* Code omitted */
    }

    [HttpGet] //Route here when firstName query param provided
    public async Task<ActionResult<IEnumerable<Student>>> SearchStudentAsync([FromQuery] string firstName)
    {
        /* Code omitted */
    }
 }

【问题讨论】:

  • 你可以做这样的事情 [HttpGet("SearchStudentAsync")] 它将路由到学生/searchstudentasync。就个人而言,我已经搜索了一种在 Http 方法属性中没有路由参数的方法,但我从未找到。
  • 谢谢@AchoVasilev。我想我可以调整路线,但我尽量保持 RESTFUL。我有一个将[HttpGet("search")] 添加到第二种方法的原型。我相信我需要使用该方法处理每个搜索查询参数的存在或缺失。
  • 试试看这个 -> stackoverflow.com/Questions/9499794/…。也许它会有所帮助。
  • 为什么不试试子控制器路由方法呢?子控制器允许您创建类似 order\1\orderdetail\2 的路线。不要使用查询参数进行路由。使用控制器和子控制器。基于参数传递的动态路由会在ui中混淆
  • @GoldenLion 我不是想通过 ID 来定位特定的学生。我正在尝试搜索具有特定属性值的学生。例如,所有名字为 Kevin 或可能在某个年级内的学生。

标签: c# routes asp.net-core-webapi asp.net-core-6.0


【解决方案1】:

您正在尝试使用 query params 区分 API 调用。这不是这样做的方法。如果你想分开通话,你应该改用path params

阅读更多关于 ASP.NET Core 中的路由 - https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-6.0

【讨论】:

  • 我修改了正确的链接。在您的问题中没有看到.net core,但无论具体框架如何,我的答案都是一样的。
  • 谢谢,我同意。我正在尝试将 Spring 的概念映射到似乎不可能的 ASP.NET。
  • 祝你好运我的朋友@KevinBowersox
【解决方案2】:

我想你正在寻找这样的东西,你需要在“HttpGet”属性中指定参数

https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-6.0#attribute-routing-with-http-verb-attributes

[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       return ControllerContext.MyDisplayRouteInfo(id);
    }

    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

【讨论】:

  • 所以这会切换到基于路由的参数。我希望坚持使用查询参数,因为最多会有 3 个。
  • 你是这个意思吗? [HttpGet("{parameter1}") [HttpGet("{parameter2}") [HttpGet("{parameter3}")
【解决方案3】:

虽然 ASP.NET Core 没有开箱即用地提供按查询参数进行过滤,但您自己提供此功能并不难。

说到可扩展性,ASP.NET 有一些超能力,IActionConstraint 就是其中之一

支持条件逻辑来确定关联的操作是否可以为给定的请求选择有效。 (Source)

创建注释以过滤查询参数非常简单

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class QueryParameterConstraintAttribute : Attribute, IActionConstraint
{
    private readonly string _parameterName;

    public QueryParameterConstraintAttribute(string parameterName)
    {
        this._parameterName = parameterName;
    }

    public bool Accept(ActionConstraintContext context)
    {
        return context.RouteContext.HttpContext.Request.Query.Keys.Contains(this._parameterName);
    }

    public int Order { get; }
}

剩下的就是用那个约束来注释你的控制器方法

[HttpGet] //Route here when firstName query param provided
[QueryParameterConstraint("firstName")]
public async Task<ActionResult<IEnumerable<Student>>> SearchStudentAsync([FromQuery] string firstName)
{
    /* Code omitted */
}

在快速测试中,我能够确认它似乎按预期工作,即使您为不同的查询参数添加了多个这些属性(如果 all 条件匹配,则调用该路由) .

(请注意,这是使用 .NET Core 2.1 测试的。无论如何,它应该与 .NET 6 几乎相同)

【讨论】:

  • 我知道有一个公认的答案,但我仍然想为这个问题提供我的解决方案,以防万一其他人正在寻找。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 2018-08-25
  • 2015-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多