自定义操作过滤器中的异步任务待处理?

时间:2017-06-03 01:37:50

标签: c# asp.net-mvc asynchronous

我需要你的帮助!我已经有一段时间了,我无法弄明白。假设我们有以下控制器:

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
}

DataBaseMyBaseController中定义的属性,如:

static ApplicationDbContext _appDbContext;
public ApplicationDbContext DataBase 
{ 
    get { return _appDbContext ?? (_appDbContext = new ApplicationDbContext()); } 
}

ApplicationDbContext继承自IdentityDbContext<MyUser>,其中MyUser继承自IdentityUser。所以,我的问题(我认为)来自自定义操作过滤器CanNotifyUserAttribute,其OnActionExecuting覆盖定义为(删除所有检查以尽可能减少):

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);
}

使用此属性的想法是验证老板是否仅向其部门的用户发送通知。现在出现了奇怪的部分,这只是在我第一次尝试向用户发送通知时发生(无论是否属于同一部门),错误源于:

  

[InvalidOperationException:在异步操作仍处于挂起状态时完成异步模块或处理程序。]

如果我尝试(在错误之后)相同的请求(即通知用户),它将按照重定向或发送通知的方式工作。

根据this post我可能会在异步任务完成之前完成请求(如果我理解的话),但我一直在使用的所有任务都是await,所以我不知道知道这个错误可能来自哪里。希望您能够帮助我。提前谢谢!

1 个答案:

答案 0 :(得分:0)

您正试图通过将OnActionExecuting变成async void来对过滤器实施异步行为。 asnyc void方法仅应在异步事件处理程序的上下文中使用,因为它们具有特殊的错误处理语义,并且调用过程“无法”等待在(filter-)方法主体内部执行的任务(对于进一步阅读,请考虑this Stephen Cleary的出色文章。

因此,对于ASP.NET Core,请考虑使用IAsyncActionFilter接口。

  

过滤器通过不同的接口定义支持同步和异步实现。异步过滤器定义单个OnStageExecutionAsync方法。此方法接受一个FilterTypeExecutionDelegate委托,该委托执行过滤器的管道阶段。   (Filters in ASP.NET Core

所以不是...

public override async void OnActionExecuting(ActionExecutingContext filterContext)

...使用:

public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

有关如何使用此功能的更多说明,请参见:Async OnActionExecuting in ASP.NET Core's ActionFilterAttribute

相关问题