使 ASP.net MVC 5 Routing Ignore Async Suffix on Action 方法

Posted

技术标签:

【中文标题】使 ASP.net MVC 5 Routing Ignore Async Suffix on Action 方法【英文标题】:Make ASP.net MVC 5 Routing Ignore Async Suffix on Action methods 【发布时间】:2016-06-07 09:25:19 【问题描述】:

WebAPI 2 智能地处理操作方法上的 Async 后缀。例如,如果我创建一个默认的 WebAPI 项目,它将路由到正确的操作,而不管后缀如何。即:

http://host/api/controller/action      - SUCCEEDS
http://host/api/controller/actionAsync - SUCCEEDS

但是,如果我使用 MVC 5 创建等效控制器,则行为会有所不同:

http://host/controller/actionAsync - SUCCEEDS
http://host/controller/action      - FAILS - 404

当 Async 后缀不存在时,它会以 404 失败,这一事实令人惊讶。尽管如此,我尝试添加一个路由来处理它,但它仍然失败:

routes.MapRoute(
    name: "DefaultAsync",
    url: "controller/actionAsync/id",
    defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional
    );

这是我用来测试的 MVC 和 WebAPI 控制器(基于具有默认路由的新 MVC/WebAPI 项目):

public class SampleDto  public string Name; public int Age; 

public class SampleMvcController : Controller

    public Task<JsonResult> GetJsonAsync()
    
        // Illustration Only. This is not a good usage of an Async method,
        // in reality I'm calling out to an Async service.
        return Task.FromResult(
            Json(new SampleDto  Name="Foo", Age = 42, JsonRequestBehavior.AllowGet));
    


public class SampleWebApiController : ApiController

    public Task<SampleDto> GetJsonAsync()
    
        return Task.FromResult(new SampleDto Name="Bar", Age=24);
    

由于我正在使一堆方法异步,我不想指定操作名称。 routing documentation 建议它可以拾取可以分隔段的文字,但我还没有运气。

更新: 问题是 MVC 检索到的 Action 包含 Async 后缀,但控制器上不存在相应的操作(或操作名称)。与动作匹配的片段MyAction 不会将MyActionAsync 识别为匹配项。

回想起来,这就是该路线行不通的原因。它尝试将操作标识为以 Async 结尾,但从匹配中使用的操作中去掉 Async 后缀,这不是我想要做的。如果我只想创建一个 MyAction 方法(这是异步但不遵循 Async 命名约定)并将其映射到相应的 MyAction 方法,这将很有用。

【问题讨论】:

可能相关***.com/questions/22664924/… 您是否将您发布的路线放在默认路线之前? @NightOwl888 - 是的,之前订购过。我已更新帖子以更好地描述实际问题。 所以,我认为你最初所说的,你的 xxxAsync 操作成功是不正确的?您的更新与您最初所说的直接矛盾。 @NightOwl888 - 不,它是正确的。当 URL 包含 &lt;action&gt;Async 而不是当 URL 仅包含 &lt;action&gt; 时,它会成功(即返回 200)。我的目标是让 MVC 看到方法 &lt;action&gt;Async 对应于从 URL 检索到的 &lt;action&gt; 所以我不需要(a)用动作名称装饰无数方法,或者(b)违反异步命名约定。 【参考方案1】:

不要尝试将文字与占位符放在一起,您应该进行约束以确保您的操作名称以 Async 结尾。

routes.MapRoute(
    name: "DefaultAsync",
    url: "controller/action/id",
    defaults: new  controller = "Home", action = "IndexAsync", id = UrlParameter.Optional ,
    constraints: new  action = @".*?Async" 
);

routes.MapRoute(
    name: "Default",
    url: "controller/action/id",
    defaults: new  controller = "Home", action = "Index", id = UrlParameter.Optional 
);

【讨论】:

约束正则表达式似乎关闭,因为它正在寻找零个或多个文字点。 @KalebPederson 我不这么认为,这意味着在零和无限字符之间,但是我认为“.+Async”会更好。 @NightOwl888 你怎么看? 这篇文章是根据我的原始评论编辑的。现在是合理的。【参考方案2】:

一开始,我对 AsyncController 类型完全实现了我们正在寻找的开箱即用功能感到非常失望。但显然它已经过时了,只是为了“向后兼容 MVC3”而存在。

所以我最终做的是制作自定义 AsyncControllerActionInvoker 并将其分配给自定义控制器的 ActionInvoker。 CustomAsyncControllerActionInvoker 覆盖 BeginInvokeAction 方法,以查看是否存在以“Async”结尾的相应操作的操作方法(例如,您传入“Index”,它会查找“IndexAsync”)。如果是,请调用那个,否则,照常继续。

public class HomeController : CustomController

    public async Task<ActionResult> IndexAsync()
    
        ViewBag.Header = "I am a page header."
        var model = new List<int> 1, 2, 3, 4, 5;
        await Task.Run(() => "I'm a task");
        return View(model);
    
    public ActionResult About()
    
        return View();
    


public class CustomController : Controller

    public CustomController()
    
        ActionInvoker = new CustomAsyncControllerActionInvoker();
    


public class CustomAsyncControllerActionInvoker : AsyncControllerActionInvoker

    public override IAsyncResult BeginInvokeAction(ControllerContext controllerContext, string actionName, AsyncCallback callback, object state)
    
        var asyncAction = FindAction(controllerContext, GetControllerDescriptor(controllerContext), $"actionNameAsync");
        return asyncAction != null
            ? base.BeginInvokeAction(controllerContext, $"actionNameAsync", callback, state)
            : base.BeginInvokeAction(controllerContext, actionName, callback, state);
    

唉,导航到 /Home/Index 会正确调用 IndexAsync() 方法并适当地提供 Index.cshtml(不是 IndexAsync.cshtml)视图。同步操作(例如“关于”)的路由按正常方式处理。

【讨论】:

以上是关于使 ASP.net MVC 5 Routing Ignore Async Suffix on Action 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使 ASP.NET MVC 登录用户超时?

ASP.net MVC 5 路由:加载基本 url 时出现 ajax 错误,但在最后添加 home/Index 时有效

ASP.NET MVC Route详解

ASP.NET MVC Route详解

详解ASP.NET MVC 路由 (上)

Routing