【问题标题】:Parameter binding to either route or querystring in ASP.NET MVC Core参数绑定到 ASP.NET MVC Core 中的路由或查询字符串
【发布时间】:2021-02-06 00:43:24
【问题描述】:

我正在将 ASP.NET MVC (.NET Framework) Web 应用程序迁移到 ASP.NET MVC Core 3.1。此应用程序是公司内部的。我们正在借此机会清理一些 API 路由以使其更加 RESTful,例如:/api/Values?id=1/api/Values/1。但是,当此应用程序投入生产时,并非所有其他应用程序都能够进行适当的更改,因此我们希望能够同时支持这两种 URL 格式。这可能吗?我的路由设置如下所示:

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.Select().Expand().Filter().OrderBy().Count().MaxTop(null);
    endpoints.EnableDependencyInjection();
    endpoints.MapODataRoute("ODataRoute", "odata", GetEdmModel());
});

我的控制器如下所示:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
    // constructor and dependency injection omitted

    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Get(int id)
    {
        // method logic omitted
    }
}

使用上面的代码,/api/Values/1 可以正常工作,但查询字符串 ?id=1 会导致 404。如果我将属性更改为 [HttpGet],那么查询字符串可以正常工作,但 RESTful 版本不能。到目前为止,这是我尝试过的:

  • [HttpGet("{id}")] + [FromQuery] – REST:404,QS:405(不允许的方法)
  • [HttpGet] + [FromQuery] [FromRoute] – 休息:404,QS:200
  • 仅限[HttpGet("{id?}")] – REST:200,QS:404

这可能吗?谢谢。

【问题讨论】:

    标签: asp.net-core routes url-routing


    【解决方案1】:

    为了达到这个要求,你可以尝试定义多条到达同一个动作的路由,如下所示。

    [HttpGet]
    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Get(int id)
    {
        if (Request.Query.TryGetValue("id",out StringValues qs_id))
        {
            int.TryParse(qs_id.FirstOrDefault(), out id);
        }
    
        //...
    
        // method logic omitted
    
        //for testing purpose 
    
        return Ok($"id is {id}");
    }
    

    测试结果

    更新:

    如果可能,您也可以尝试实现并使用 URL Rewrite Rule(s) 来实现。

    <rule name="id qs rule">
        <match url="api/values" />
        <conditions>
              <add input="{PATH_INFO}" pattern="api/values$" />
              <add input="{QUERY_STRING}" pattern="id=([0-9]+)" />
        </conditions>
        <action type="Rewrite" url="api/values/{C:1}/" appendQueryString="false" />
    </rule>
    

    测试结果

    【讨论】:

    • 好吧,我应该想到的。这似乎相当明显,如果有点破解的话。不过,我希望有一些更优雅的东西。
    • 嗨@howcheng,您可以尝试使用URL重写规则的另一种方法,有关详细信息,请查看我的更新。
    • 我终于回到了这个问题,但在重写规则方面遇到了麻烦。我在stackoverflow.com/questions/66234483/…提出了一个新问题
    猜你喜欢
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多