问题
Let's say I have a ASP.NET Core 3.0 MVC application, which features a simple controller containing two actions and using attribute based routing:
[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());
}
}
So calling either action should just yield a page showing URLs for both actions.
Opening /home/a1
and /home/a2
correctly calls the respective actions, but the output is kind of unexpected:
Action1: '/home/a1'
Action2: ''
This indicates that Url.Action()
returned an empty string for the second action, while it worked perfectly fine for the first action.
After debugging this for quite a while, I found a blog post tracking down this very problem to a breaking change in ASP.NET Core 3.0, where the Async
suffix is somehow ignored by Url.Action()
.
The author fixed this problem by hard-coding strings as action names ("Action1"
und "Action2"
in my case). He also uploaded some example code reproducing this behavior.
However, I would really prefer to keep the nameof
, to avoid later problems with renaming/refactoring.
Is there a clean way to use nameof
or other type-safe constructs to supply a method with Async
suffix to the Url.Action
function?
回答1:
The described behavior is caused by a breaking change introduced with ASP.NET Core 3.0.
You can go back to the old behaviour by disabling SuppressAsyncSuffixInActionNames:
Gets or sets a value that determines if MVC will remove the suffix "Async" applied to controller action names.
Disable this switch in your AddControllers
call while configuring the application services:
services.AddControllers(options => {
options.SuppressAsyncSuffixInActionNames = false;
});
You can find more information about this change in the official announcement and in the docs.
回答2:
If you change your method name Action2Async to Action2 the problem will be solved.
From the linked 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());
}
来源:https://stackoverflow.com/questions/59969091/using-nameof-with-url-action-and-async-methods-in-asp-net-core-3-x-mvc