【问题标题】:Getting a 404 with asynchronous action (Task<ActionResult>)使用异步操作获取 404 (Task<ActionResult>)
【发布时间】:2014-10-08 06:49:17
【问题描述】:

很简单,我已经将一些同步登录操作转换为异步,现在找不到它们,得到 404。

    public async Task<ActionResult> BetaLoginAsync()
    {            
        return View();
    }

    [HttpPost]
    public async Task<ActionResult> BetaLoginAsync(Models.Authentication.SimpleLoginModel loginModel, string returnUrl)
    {
        if (this.ModelState.IsValid)
        {
            if (await this.ValidateCredentialsAsync(loginModel))
            {
    ...

我以为我已经完成了所有需要的,我遵循了这个:

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

编译器警告我,第一个只返回视图的操作方法没有使用 await 关键字,因此它将同步运行。

问题是当我删除async 关键字时,它根本无法编译。编译器说调用View返回的类型ViewResult不能隐式转换为类型Task&lt;ActionResult&gt;

现在,如果我让它同步但保留我的HttpPost 回发登录验证方法异步,那么当我单击提交按钮时,MVC 路由不会调用它,而是发布到只返回视图的同步版本!!

我以前使用过异步操作,但我不知道为什么今天我在挣扎。

当有两个同名/重载的操作方法时,这是一个错误吗??

有人知道怎么回事吗?

更新 1

好吧,这很奇怪。

当控制器子类化 AsyncController 时它可以工作,但这不应该是它在 MVC 4+ 中的工作方式。

我应该在 ASP.NET MVC 4 中使用 AsyncController 吗?

我正在运行 MVC 5,或者应该是。我已经有……年没有创建 MVC 3 项目了。

我需要做更多调查然后回来。

更新 2

我有一个答案,但没有真正理解为什么。我尝试了 Chris 的建议,即从操作中删除 Async 后缀,它奏效了。

奇怪的是,如上所述,它在使用 MVC 3 中的“旧”AsyncController 时有效。

我想这就是现在的样子。

【问题讨论】:

  • 您能告诉我们您发送到服务器的GETPOST。您是否更新了您正在使用的网址以包含 Async 后缀?顺便说一句,Async 后缀不是必需的。它只是用于演示代码。
  • Async 后缀是 convention。只有当被调用的方法实际上是异步执行时才应该添加它。
  • 嗨 Jeff,在 MVC 5 的情况下(使用最近的 Controller 类),似乎可以忽略这个约定;路由不会“看到”附加了“异步”的操作。

标签: c# asp.net-mvc asp.net-mvc-4 asynchronous


【解决方案1】:

也许 MVC 不匹配同名的同步和异步操作。

也就是说,BetaLoginAsync() 就目前而言很好。没有异步工作要做。这是该警告的误报情况。

如果您愿意,可以使用return Task.FromResult(View());。没关系。

【讨论】:

    【解决方案2】:

    异步方法必须有一些东西可以等待。否则,它没有提示何时允许返回其线程,因此将运行同步(始终保持线程)。警告就是:警告。它让您知道您通过使方法异步来增加开销,但实际上并未执行任何异步工作,因此只是无缘无故地增加开销。

    删除async 时出错的原因是您仍在返回Task&lt;ActionResult&gt;。所以如果要去掉async,其实需要把方法定义改成:

    public ActionResult BetaLoginAsync()
    

    然后,它将编译没有错误或警告。

    显然此时命名很尴尬,但是您的两个方法名称必须匹配,以允许路由框架回发到相同的 URL(没有属性路由)。

    然而,看到以Async 命名的异步控制器操作实际上是闻所未闻的。

    对于其他类型的方法遵循该约定是很常见的,因为它为程序员提供了他们需要等待该方法的线索。但是,通常情况下,您实际上并不直接调用控制器操作方法,这消除了约定的好处。除非您喜欢 Async 出现在您的 URL 中(这是您不应该的),否则它还会使传统路由变得更加困难。

    所以,我会从这两种方法中删除 Async 后缀。

    【讨论】:

    • 感谢您的回答。即使我在Task.Delay(1) 上添加了一些“假”等待,它也无法工作,直到我将AsyncController 子类化。我不应该那样做。我还在尝试。
    • 好的,所以它的 ..Async 后缀不适用于 MVC 5 Controller 基类,但适用于 AsyncController 基类。关于Async 后缀,这篇文章似乎是错误的,但是看看我的其他项目,我以前使用过这个后缀。诡异的。我无法解释有什么不同。
    • 我想这与方法名称有关。除非您实际上要在浏览器中访问 /Something/BetaLoginAsync 或为其设置自定义路由,否则您不会从传统控制器中执行操作。 AsyncController 可能有一些约定,为了路由,它会从操作名称中删除 Async 部分,尽管我只是在猜测。
    • 据我所知,本教程只是使用Async 后缀来区分同步与异步示例。回想起来,这对作者来说可能是一个糟糕的选择,因为它似乎鼓励以这种方式命名你的行为。不过,我不相信那是意图。
    • 这不是错误。这可能会产生误导,但那里的每一段代码都会运行。
    【解决方案3】:

    克里斯有正确的答案。当我写Using Asynchronous Methods in ASP.NET MVC 4 时,没有建立命名异步操作方法的约定。后缀只是约定,与异步无关(如文档所述 - “Async”附加到方法名称。附加“Async”不是必需的,但在编写异步方法时是约定。 - 正如克里斯指出这是惯例,但不适用于 MVC 应用程序

    您的转换失败的原因是您错过了这一点,而使用旧 AsyncController 的原因是旧 AsyncController 依赖于 async 后缀。查看源代码,您可以看到。另请查看源代码,您可以看到 AsyncController 现在只是一个控制器,因为控制器基类支持异步。 AsyncController 只是为了向后兼容而留在代码库中。

    创建一个新的 MVC 5 应用,添加一个模型,创建一个控制器并选中异步框。检查工作的异步代码,也许这会帮助你找出你做错了什么。异步 MVC 非常常见且被广泛使用。

    【讨论】:

    • 感谢您回复我,瑞克。我已经弄清楚了所有的困惑在哪里。在我的 URL 中,我没有附加异步,所以它没有找到动作。这听起来可能很明显,但我希望框架能够修剪 Async 后缀,就像它如何修剪“控制器”一样,因为它只是一个约定,但也因为这就是它过去与 AsyncController 一起工作的方式——自从我改变了它最后一次使用它,这让我很震惊。所以,不,没有错误,抱歉,但 URL 必须更改的事实并没有向读者突出显示。
    • @Luke Puplett - 如果我有时间,我会更新文章,我知道这可能会造成混乱。
    猜你喜欢
    • 2019-06-23
    • 2016-05-30
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多