首页 > 解决方案 > 在 Razor Pages 应用程序中获取 Web api 控制器方法的 URL?

问题描述

我在 /Pages 文件夹下有 index.cshtml。和同一文件夹中的 web api 控制器:

[Route("api/[controller]")]
[ApiController]
public class ValuesController: ControllerBase
{
    [HttpGet]
    public IEnumerable<string> GetValue(){
        return new string[] { "value1", "value2" };
    }
}

现在我预计这段代码应该可以工作(因为它在 Asp Core 2 中工作):

var apiUri = Url.Action(action: "GetValue", controller: "Values");
var apiUri2 = Url.ActionLink(action: "GetValue", controller: "Values");

但它不起作用(返回空值)!以及我尝试过的所有其他选项:

 var apiUri3 = Url.Action(action: "GetValue", controller: "ValuesController");

如何强制Url.ActionCORE 3(4 和 5)中的 web api 控制器工作?

这是IActionDescriptorCollectionProvider.ActionDescriptors.Items信息:在此处输入图像描述

项目结构(实际上是核心网络应用程序):

在此处输入图像描述

命令窗口结果:

>? Url.Action(action: "GetValue", controller: "Values");
null
>? Url.Action(action: "GetValue", controller: "ValuesController");
null
>? Url.Action(action: "Value", controller: "ValuesController");
null
>? Url.Action(action: "Value", controller: "Values");
null
>

对于那些减去“明显”(我猜)的人,测试自己:

  1. [ApiController] 注释掉(控制器没有标记为 ApiController);[Route("api/[controller]/[action]")] 添加;没有端点。* 修改 - 控制器是否“可路由”?(回答“不”)
  2. 仍然不是 [ApiController] 但现在我们添加 endpoints.MapControllerRoute("default", "api/[controller]/[action]"); - 控制器是“可路由的”吗?(回答“是”)
  3. 现在我们另外 (2) 注释掉 [Route("api/[controller]/[action]")] - 控制器是“可路由的”吗?(回答“不”)
  4. 现在返回 [Route("api/[area]/[controller]/[action]")] 但还要添加 [ApiController] 并添加 [Area("myarea")] 控制器是否“可路由”?(回答“不”)

标签: c#asp.net-coreasp.net-core-3.1asp.net-core-5.0

解决方案


它不起作用的原因是 ApiController 的路由工作方式不同。

在您的示例中:

[Route("api/[controller]")]
[ApiController]
public class ValuesController: ControllerBase
{
    [HttpGet]
    public IEnumerable<string> GetValue(){
        return new string[] { "value1", "value2" };
    }
}

假设这在 localhost

真正意味着路由是“http://localhost/api/Values”

例如,如果您想要“http://localhost/api/Values/GetValue”,您需要执行以下操作:

[Route("api/[controller]")]
[ApiController]
public class ValuesController: ControllerBase
{
    [HttpGet("GetValue")]//notice the extra piece of route we added here
    public IEnumerable<string> GetValue()
    {
        return new string[] { "value1", "value2" };
    }

    [HttpGet("GetAnotherValue")]//notice the extra piece of route we added here
    public IEnumerable<string> GetValue()
    {
        return new string[] { "value1", "value2" };
    }
}

至于使用 Url.Action 你可能会使用类似的东西:

///api/Values/GetValue"
var apiUri1 = Url.Action(action: "GetValue", controller: "Values");

///api/Values/GetAnotherValue"
var apiUri2 = Url.Action(action: "GetAnotherValue", controller: "Values");

最后,您需要确保映射了 api 控制器路由

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers(); // Map attribute-routed API controllers
    //endpoints.MapDefaultControllerRoute(); // Map conventional MVC controllers using the default route
    endpoints.MapRazorPages();//map razor pages
});

最后,您的“ApiController”控制器不需要位于“Pages”文件夹中。Api 控制器按属性路由,而不是按“文件夹位置”。我建议您将它们放在项目根目录中名为 Controllers 的文件夹中。

这篇文章中的另一个答案似乎“有效”,但是一旦您向 API 控制器添加另一个操作,您就会意识到它会在 Url.Action 调用中产生错误的 url,因为在 ApiControllers 中,路由不会通过“方法名称”发生"


推荐阅读