Very simply, I've converted some synchronous login actions to asynchronous and now they're not found, getting 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))
{
...
I thought I'd done all that's needed, I followed this:
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
The compiler is warning me that the first action method that just returns a view isn't using the await
keyword, so it will run synchronously.
The problem is that when I remove the async
keyword, it then doesn't compile at all. Compiler says that the type ViewResult
returned from the call to View
cannot be implicitly converted to type Task<ActionResult>
.
Now, if I make it synchronous but leave my HttpPost
post-back login validation method asynchronous, then MVC routing doesn't call it when I click the submit button, instead it posts to the synchronous version that just returns the view!!
I've worked with asynchronous actions before, I don't know why I'm struggling today.
Is this a bug when there are two action methods with the same name/overloaded??
Does anyone know what's going on?
Update 1
Okay, so this is weird.
It works when the controller subclasses AsyncController but this is not supposed to be how it works in MVC 4+.
Should I use AsyncController at ASP.NET MVC 4?
I'm running MVC 5, or supposed to be. I haven't created an MVC 3 project for ...years.
I'll need to do some more investigating and come back.
Update 2
I have an answer, but no real understanding of why. I tried Chris' suggestion of removing the Async
suffix from the actions and it worked.
The strange thing is that, as above, it works when using the 'old' AsyncController
from MVC 3.
I guess that's just how it is now.
An asynchronous method must have something to wait on. Otherwise, it has no cue for when it's allowed to return its thread and will therefore run sync (hold on to the thread the entire time). The warning is just that: a warning. It's letting you know that you're adding overhead by making the method async but not actually doing any asynchronous work and, therefore, are just adding overhead for no reason.
The reason you got an error with removing async
is that you're still returning a Task<ActionResult>
. So if you want to remove async, you actually need to change the method definition to:
public ActionResult BetaLoginAsync()
Then, it will compile without error or warning.
Obviously the naming is awkward at that point, but your two method names must match up to allow the routing framework to do a postback to the same URL (without attribute routing).
However, it's actually pretty unheard of to see async controller actions named with Async
.
It's common to follow that convention for other types of methods, because it provides a clue to the programmer that they need to await the method. However, you don't actually call controller actions methods directly, typically, which removes the benefit of the convention. It also makes traditional routing more difficult unless you like Async
showing up in your URLs (which you shouldn't).
So, I would just remove the Async
suffix from both methods.
Chris has the right answers. When I wrote Using Asynchronous Methods in ASP.NET MVC 4 there was no established convention for naming async action methods. The suffix is just convention and has nothing to do with async (as the document states - "Async" was appended to the method name. Appending "Async" is not required but is the convention when writing asynchronous methods.- As Chris points out that's the convention, but not for MVC apps)
The reason your conversion didn't work is you missed that point, and the reason using the old AsyncController works, is the old AsyncController depended on the async suffix. Look at the source code and you can see that. Also look at the source code and you can see an AsyncController just a controller now since the controller base class supports async. AsyncController was just left in the code base for backward compatibility.
Create a new MVC 5 app, add a model, create a controller and check the async box. Examine the working async code and maybe that will help you figure out what you're doing wrong. Async MVC is very common and widely used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With