自定义操作过滤器中有待处理的异步任务? [英] Asynchronous task pending in custom action filter?
问题描述
我需要您的帮助!我已经解决了好一阵子了,但我一直无法弄清楚.假设我们有以下控制器:
I need your help! I've been a while around this and I haven't been able to figure it out. Let's suppose we have the following controller:
class NotifierController : MyBaseController {
...
[HttpGet]
[CanNotifyUser]
public async Task<ActionResult> NotifyUser(string id)
{
return View(await DataBase.Users.FindAsync(id));
}
// More actions decorated with the CanNotifyUserAttribute attribute
}
DataBase
是在MyBaseController
中定义的属性,例如:
DataBase
is a property defined in MyBaseController
like:
static ApplicationDbContext _appDbContext;
public ApplicationDbContext DataBase
{
get { return _appDbContext ?? (_appDbContext = new ApplicationDbContext()); }
}
ApplicationDbContext
从IdentityDbContext<MyUser>
继承,其中MyUser
从IdentityUser
继承.因此,我的问题(我认为)来自自定义操作过滤器CanNotifyUserAttribute
,其OnActionExecuting
替代定义为(删除所有检查以尽可能减少):
ApplicationDbContext
inherits from IdentityDbContext<MyUser>
where MyUser
inherits from IdentityUser
. So, my problem (I think) comes to the custom action filter CanNotifyUserAttribute
, whose OnActionExecuting
override is defined as (removing all checks to reduce as much as possible):
public override async void OnActionExecuting(ActionExecutingContext filterContext)
{
NotifierController controller = filterContext.Controller as NotifierController;
Boss boss = await controller.DataBase.Bosses.FindAsync(filterContext.HttpContext.User.Identity.GetUserId());
object id = filterContext.ActionParameters["id"];
User user = await controller.DataBase.Users.FindAsync(id.ToString());
if (user.Department.Id != boss.Department.Id)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
action = "Login",
controller = "Account",
returnUrl = controller.Url.Action("NotifyUser", new { id = id })
}));
}
base.OnActionExecuting(filterContext);
}
具有此属性的想法是验证老板仅将通知发送给其部门的用户.现在出现了一个奇怪的部分,这仅在我第一次尝试向用户发送通知(无论它是否属于同一部门)时发生,错误提示是:
The idea with this attribute is to verify that a boss sends notifications to the users of his department only. Now comes the strange part, this only happens the first time I try to send a notification to an user (no matter whether it's of the same department or not), the error thronw is:
[InvalidOperationException:异步模块或处理程序在异步操作仍处于挂起状态时完成.]
[InvalidOperationException: An asynchronous module or handler completed while an asynchronous operation was still pending.]
如果我尝试(在错误发生后)相同的请求(即通知用户),则该请求的工作方式如扩展重定向或发送通知.
If I try (after the error) the same request (i.e., notify the user) it works as expexted either redirecting or sending the notification.
根据这篇文章在异步任务完成之前,我可能已经完成了请求(如果我理解得很好),但是我一直在使用的所有任务都被await
了,所以我不知道此错误可能来自何处.希望您能够帮助我.预先感谢!
According to this post I might be finishing the request (If I understood well) before an asynchronous task is finished, but all the tasks I've been using are all await
ed so I don't know where this error may come from. Hope you can help me. Thanks in advance!
推荐答案
您正试图通过将OnActionExecuting
转换为async void
来对过滤器实施异步行为. asnyc void
方法仅应在异步事件处理程序的上下文中使用,这是由于其特殊的错误处理语义以及调用过程无法"等待(过滤方法)体内执行的任务(以供进一步阅读)的原因. ,请考虑这篇 Stephen Cleary的出色文章).
You are trying to enforce async behaviour on your filter by turning OnActionExecuting
into an async void
. asnyc void
methods should only be used in the context of asynchronous event handlers due to their special error-handling semantics and the "inability" of the calling process to wait for the tasks executed inside your (filter-)method's body (for further reading, consider this great article by Stephen Cleary).
Therefore, with ASP.NET Core, consider using the IAsyncActionFilter interface instead.
过滤器通过不同的接口定义支持同步和异步实现.异步过滤器定义单个OnStageExecutionAsync方法.此方法接受一个FilterTypeExecutionDelegate委托,该委托执行过滤器的管道阶段. ( ASP.NET中的过滤器核心)
Filters support both synchronous and asynchronous implementations through different interface definitions. [...] Asynchronous filters define a single OnStageExecutionAsync method. This method takes a FilterTypeExecutionDelegate delegate which executes the filter's pipeline stage. (Filters in ASP.NET Core)
所以不是...
public override async void OnActionExecuting(ActionExecutingContext filterContext)
...用途:
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
有关如何使用此功能的更多说明,请参见:在ASP中执行异步OnActionExecuting. NET Core的ActionFilterAttribute
For further instructions on how to use this see: Async OnActionExecuting in ASP.NET Core's ActionFilterAttribute
这篇关于自定义操作过滤器中有待处理的异步任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!