【问题标题】:Routing a selection of controller methods to the root URL of the web API将一系列控制器方法路由到 Web API 的根 URL
【发布时间】:2020-07-17 11:32:59
【问题描述】:

我正在将旧版 .NET 应用程序移植到 .NET Core Web API。

旧版应用程序公开了一个我必须 1:1 移植的 API。

我的以下请求路径运行良好:

GET https://localhost:5001/MySuperController/user@example.com
GET https://localhost:5001/MySuperController/?username=user@example.com
POST https://localhost:5001/MySuperController/?username=user@example.com

swagger: GET https://localhost:5001/doc

但是我在路由以下两条路径到达根 URL 时遇到问题:

GET https://localhost:5001/?username=user@example.com
POST https://localhost:5001/?username=user@example.com

这是我的控制器和招摇注册:

app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
if (EnvironmentConfiguration.EnvironmentType == SystemConstants.DevEnvironment)
{
    app.UseSwagger(s =>
    {
        s.RouteTemplate = "doc/{{documentName}}/docs.json";
    });
    app.UseSwaggerUI(c =>
    {
        c.RoutePrefix = "doc";
        c.SwaggerEndpoint($"../doc/v1/docs.json", "API reference");
    });
}

这是控制器的简化实现:

[Route("[controller]")]
[ApiController]
public class MySuperController
{
    // GET https://localhost:5001/MySuperController/user@example.com
    [HttpGet("{emailaddress}")]
    public IActionResult Get(...) {...}

    // GET https://localhost:5001/MySuperController/?username=user@example.com
    [HttpGet()]
    public IActionResult Get(...) {...}

    // POST https://localhost:5001/MySuperController/?username=user@example.com
    [HttpPost()]
    public async Task<IActionResult> Post(...) {...}
}

为了支持以下两个查询,我添加了[Route("")] 前缀。但现在我将https://localhost:5001/doc 匹配到第一个控制器操作中,{emailaddress} 被"doc" 填充。

GET https://localhost:5001/?username=user@example.com
POST https://localhost:5001/?username=user@example.com
[Route("[controller]")]
[Route("")]
[ApiController]
public class MySuperController
{
    // also matches https://localhost:5001/doc now :(
    // GET https://localhost:5001/MySuperController/user@example.com
    [HttpGet("{emailaddress}")]
    public IActionResult Get(...) {...}

    // GET https://localhost:5001/?username=user@example.com
    // GET https://localhost:5001/MySuperController/?username=user@example.com
    [HttpGet()]
    public IActionResult Get(...) {...}

    // POST https://localhost:5001/?username=user@example.com
    // POST https://localhost:5001/MySuperController/?username=user@example.com
    [HttpPost()]
    public async Task<IActionResult> Post(...) {...}
}

使用 Web API 正确路由这些查询的最惯用方法是什么?如果可能的话,我不希望将控制器拆分为多个控制器。

【问题讨论】:

  • 如果你把[Route("/my/path-to-something")] 放在动作方法上,你可以明确定义它们的所有URL。
  • 我在移植应用程序时也遇到了复杂的路由问题。然后我使用了DynamicRouteValueTransformer。见这里:github.com/dotnet/AspNetCore.Docs/issues/12997 你可以在app.useEndpoings(endpoints =&gt; endpoints.MapDynamicControllerRoute&lt;MyTransforer&gt;(...) 注册它。在这个转换器中,您拥有带有所有查询参数的 httpContext、asp.net 将使用的 RouteValueDictionary,您可以使用任何逻辑来更改该路由。
  • @MartinCostello 感谢您为我指明了正确的方向!
  • @gofal3 感谢您的想法!幸运的是,在没有您链接的真正大工具的情况下,我设法解决了问题:D

标签: c# asp.net asp.net-core asp.net-web-api


【解决方案1】:

非常感谢 Martin Costello 的评论,我得出以下结论:

[ApiController]
public class MySuperController
{
    [HttpGet("[controller]/{emailaddress}")]
    public IActionResult Get(...) {...}

    [HttpGet("[controller]")]
    [HttpGet("/")]
    public IActionResult Get(...) {...}

    [HttpPost("[controller]")]
    [HttpPost("/")]
    public async Task<IActionResult> Post(...) {...}
}

这样,/ 的 GET 和 POST 都可以通过正确的操作得到解决,而/doc 和任何其他端点都不会被第一种方法拦截,而是保留在控制器之下。

【讨论】:

    猜你喜欢
    • 2015-09-10
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 2016-09-07
    • 1970-01-01
    • 2017-10-01
    相关资源
    最近更新 更多