.NET MVC异步方法异常场景下Completed方法调用及处理问询
Great questions—this stuff can get tricky with the traditional MVC async controller pattern, so let’s break it down clearly.
1. Does the Completed method run if the async method throws an exception?
Quick answer: Nope, not by default.
In the classic MVC async setup (where you have a [ActionName]Async method paired with a [ActionName]Completed method, using AsyncManager), an unhandled exception in the async operation will break the workflow entirely. The MVC framework won’t trigger the corresponding Completed method—it skips that step and moves straight to handling the error.
2. Deep dive into traditional .NET MVC async behavior
Let’s unpack each part of your follow-up:
When would BlahCompleted() get called if the main method throws an exception?
Almost never. The Completed method only runs if two conditions are met:
- All operations tracked by
AsyncManager.OutstandingOperationshave finished (meaning the count hits 0 after calls toDecrement()), and - No unhandled exceptions were thrown during the entire async workflow.
If the main BlahAsync method throws an exception before starting the async work, or if the async operation itself blows up with an unhandled exception, the framework abandons the process—BlahCompleted() will never execute.
How is the exception handled, and does the caller get an error code?
The unhandled exception falls into MVC’s standard exception pipeline:
- If you’ve set up a global exception filter or overridden
OnExceptionin your controller, that code will process the error first. - Without custom handling, MVC sends a default
500 Internal Server Errorresponse to the caller. So yes, the client will receive a standard HTTP error code (usually 500 for unhandled server-side issues).
Does calling AsyncManager.OutstandingOperations.Increment() change this?
Definitely—here’s the breakdown:
- If you call
Increment()but the async operation throws an exception without callingDecrement(), theOutstandingOperationscount never reaches 0. MVC will wait for that count to drop, eventually hitting the async timeout (default is ~90 seconds). When this happens, a timeout exception is thrown, which still skips theCompletedmethod and triggers an error response. - If you don’t use
OutstandingOperationsat all, the framework treats the async method as done as soon as the main method exits. Any exception thrown during that exit is handled immediately, no waiting involved.
内容的提问来源于stack exchange,提问作者Oliver Bock

