在 ASP.NET Core 3.x MVC 中将 nameof() 与 Url.Action() 和异步方法一起使用
Using nameof() with Url.Action() and async methods in ASP.NET Core 3.x MVC
假设我有一个 ASP.NET Core 3.0 MVC 应用程序,它具有一个包含两个操作并使用基于属性的路由的简单控制器:
[Route("home")]
public class HomeController : Controller
{
public static string ControllerName { get; } = "Home";
public HomeController()
{
}
string GenerateUrls()
{
string url1 = Url.Action(nameof(Action1), ControllerName);
string url2 = Url.Action(nameof(Action2Async), ControllerName);
return $"Action1: '{url1}'\nAction2: '{url2}'";
}
[HttpGet("a1")]
public IActionResult Action1()
{
return Ok(GenerateUrls());
}
[HttpGet("a2")]
public async Task<IActionResult> Action2Async()
{
await Task.CompletedTask;
return Ok(GenerateUrls());
}
}
因此调用任一操作应该只会生成一个显示两个操作的 URL 的页面。
打开 /home/a1
和 /home/a2
正确调用了相应的操作,但输出有点出乎意料:
Action1: '/home/a1'
Action2: ''
这表明 Url.Action()
为第二个操作返回了一个空字符串,而它在第一个操作中工作得很好。
调试了一段时间后,我发现了一个 blog post 追踪这个问题到 ASP.NET Core 3.0 中的一个突破性变化,其中 Async
后缀被莫名其妙地忽略了通过 Url.Action()
.
作者通过将字符串硬编码为动作名称(在我的例子中为 "Action1"
和 "Action2"
)解决了这个问题。他还上传了一些重现此行为的 example code。
不过,我真的更愿意保留 nameof
,以避免以后 renaming/refactoring 出现问题。
是否有一种干净的方法来使用 nameof
或其他类型安全的构造来为 Url.Action
函数提供带有 Async
后缀的方法?
如果将方法名称 Action2Async 更改为 Action2,问题将得到解决。
来自链接 blog post:
In ASP.NET Core 3, if you have Action methods suffixed with Async but a route path that does not include Async, refer to them without the Async suffix when resolving a URL through like Url.Action(). This seems to be a breaking change from ASP.NET Core 2.2 which is not officially documented.
public static string ControllerName { get; } = "Home";
string GenerateUrls()
{
string url1 = Url.Action(nameof(Action1), ControllerName);
string url2 = Url.Action(nameof(Action2), ControllerName);
return $"Action1: '{url1}'\nAction2: '{url2}'";
}
[HttpGet("action1")]
public IActionResult Action1()
{
return Ok(GenerateUrls());
}
[HttpGet("action2")]
public async Task<IActionResult> Action2()
{
await Task.CompletedTask;
return Ok(GenerateUrls());
}
所描述的行为是由 ASP.NET Core 3.0 引入的重大更改引起的。
您可以通过禁用 SuppressAsyncSuffixInActionNames
返回到旧行为:
Gets or sets a value that determines if MVC will remove the suffix "Async" applied to controller action names.
在配置应用程序服务时在 AddControllers
调用中禁用此开关:
services.AddControllers(options => {
options.SuppressAsyncSuffixInActionNames = false;
});
您可以在 official announcement and in the docs.
中找到有关此更改的更多信息
假设我有一个 ASP.NET Core 3.0 MVC 应用程序,它具有一个包含两个操作并使用基于属性的路由的简单控制器:
[Route("home")]
public class HomeController : Controller
{
public static string ControllerName { get; } = "Home";
public HomeController()
{
}
string GenerateUrls()
{
string url1 = Url.Action(nameof(Action1), ControllerName);
string url2 = Url.Action(nameof(Action2Async), ControllerName);
return $"Action1: '{url1}'\nAction2: '{url2}'";
}
[HttpGet("a1")]
public IActionResult Action1()
{
return Ok(GenerateUrls());
}
[HttpGet("a2")]
public async Task<IActionResult> Action2Async()
{
await Task.CompletedTask;
return Ok(GenerateUrls());
}
}
因此调用任一操作应该只会生成一个显示两个操作的 URL 的页面。
打开 /home/a1
和 /home/a2
正确调用了相应的操作,但输出有点出乎意料:
Action1: '/home/a1'
Action2: ''
这表明 Url.Action()
为第二个操作返回了一个空字符串,而它在第一个操作中工作得很好。
调试了一段时间后,我发现了一个 blog post 追踪这个问题到 ASP.NET Core 3.0 中的一个突破性变化,其中 Async
后缀被莫名其妙地忽略了通过 Url.Action()
.
作者通过将字符串硬编码为动作名称(在我的例子中为 "Action1"
和 "Action2"
)解决了这个问题。他还上传了一些重现此行为的 example code。
不过,我真的更愿意保留 nameof
,以避免以后 renaming/refactoring 出现问题。
是否有一种干净的方法来使用 nameof
或其他类型安全的构造来为 Url.Action
函数提供带有 Async
后缀的方法?
如果将方法名称 Action2Async 更改为 Action2,问题将得到解决。
来自链接 blog post:
In ASP.NET Core 3, if you have Action methods suffixed with Async but a route path that does not include Async, refer to them without the Async suffix when resolving a URL through like Url.Action(). This seems to be a breaking change from ASP.NET Core 2.2 which is not officially documented.
public static string ControllerName { get; } = "Home";
string GenerateUrls()
{
string url1 = Url.Action(nameof(Action1), ControllerName);
string url2 = Url.Action(nameof(Action2), ControllerName);
return $"Action1: '{url1}'\nAction2: '{url2}'";
}
[HttpGet("action1")]
public IActionResult Action1()
{
return Ok(GenerateUrls());
}
[HttpGet("action2")]
public async Task<IActionResult> Action2()
{
await Task.CompletedTask;
return Ok(GenerateUrls());
}
所描述的行为是由 ASP.NET Core 3.0 引入的重大更改引起的。
您可以通过禁用 SuppressAsyncSuffixInActionNames
返回到旧行为:
Gets or sets a value that determines if MVC will remove the suffix "Async" applied to controller action names.
在配置应用程序服务时在 AddControllers
调用中禁用此开关:
services.AddControllers(options => {
options.SuppressAsyncSuffixInActionNames = false;
});
您可以在 official announcement and in the docs.
中找到有关此更改的更多信息