Using nameof() with Url.Action() and async methods in ASP.NET Core 3.x MVC

给你一囗甜甜゛ 提交于 2020-02-25 01:52:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!