.NET Core (2.1) web API 控制器接受请求 url 中的所有后续内容作为参数

.NET Core (2.1) web API controller accepting all that follows within the request url as parameter

我拥有的是一个 .NET Core 2.1 web API 控制器(在下面的 TestController 中),它应该在接收 GET 请求时生成到其他 url 的重定向。

示例:

控制器的调用方式如下:http://localhost/api/v1/Test/somedir/somesubdir/filename.extension

它应该 return 重定向到 https://example-domain.com/somedir/somesubdir/filename.extension

这个问题的示例控制器如下所示:

  [Authorize]
  [Route("api/v1/[controller]")]
  public class TestController : ControllerBase
  {
    [HttpGet("{path}")]
    public async Task<IActionResult> Get(string path)
    {
      //path e.g. is somedir/somesubdir/filename.extension
      string prefix = "https://example-domain.com/api/v1/Other/";
      //string path2 = HttpContext.Request.Path.Value.Replace("/api/v1/Test/", "/api/v1/Other/").Replace("%2F", "/");
      return Redirect(prefix + path);
    }
  }

我无法使用路由。如果我使用 Swagger 调用该方法,它会被调用(斜杠被 %2F 替换)但至少它会被调用。 如果我通过 postman .NET Core 调用控制器只是 returns 404 Not Found.

我不一定需要 HttpGet("{path}")。我知道我可以获得路径,就像我分配 path2 变量一样。

有什么提示可以让我获得正确的路由吗?


另一种可能的解决方案:

正如 John 和 Kirk Larkin 在评论中所指出的,我正在寻找的是一条包罗万象的路线,用 "somedir/somesubdir/filename.extension" 填充路径参数,独立于之后的路径有多长。

只需在变量名前加一个星号即可。

[HttpGet("{*path}")]

我认为您需要像 URL 中那样接收这 3 个分开的参数,所以..该方法应该是这样的...

[Route("{dir}/{subdir}/filename")]
public async Task<IActionResult> Get(string dir, string subdir, string filename)
{
  string path = dir + "/" + subdir + "/" + filename;
  //path e.g. is somedir/somesubdir/filename.extension
  string prefix = "https://example-domain.com/api/v1/Other/";
  //string path2 = HttpContext.Request.Path.Value.Replace("/api/v1/Test/", "/api/v1/Other/").Replace("%2F", "/");
  return Redirect(prefix + path);
}

@john,他的解决方案很棒:[HttpGet("{*path}")],刚测试过。但我想保留我对功能使用的回答作为一个选项:

作为另一种选择,您可以遵循 MSDN [Catch-all route]:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.1

routes.MapRoute(
  name: "blog",
  template: "Blog/{*article}", //<==
  defaults: new { controller = "Blog", action = "ReadArticle" });

This template will match a URL path like /Blog/All-About-Routing/Introduction and will extract the values { controller = Blog, action = ReadArticle, article = All-About-Routing/Introduction }. The default route values for controller and action are produced by the route even though there are no corresponding route parameters in the template. Default values can be specified in the route template. The article route parameter is defined as a catch-all by the appearance of an asterisk * before the route parameter name. Catch-all route parameters capture the remainder of the URL path, and can also match the empty string.

最后的选择是:不使用控制器,在全局配置中使用:

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.Map("api/v1/Test", x =>
        {
            x.Run(async context =>
            {
                //path e.g. is somedir/somesubdir/filename.extension
                string prefix = "https://example-domain.com/api/v1/Other/";
                string path = context.Request.Path.Value.Replace("/api/v1/Test/", "/api/v1/Other/").Replace("%2F", "/");
                context.Response.Redirect(prefix + path);
            });
        });
    }
}

您不需要像您的代码注释所建议的那样考虑 "api/v1/Test",它已经被 Controller 级别的 [Route] 属性过滤掉了。

对于接下来的路径,您可以使用 {*path}:

[HttpGet("{*path}")]
public async Task<IActionResult> Get(string path)
{
    const string prefix = "https://example-domain.com/api/v1/Other/";
    return Redirect(prefix + path);
}