【问题标题】:Perform Async operation asp.net mvc outside of the action在操作之外执行异步操作 asp.net mvc
【发布时间】:2021-09-25 01:34:43
【问题描述】:

我希望能够在每个请求上从云数据库加载用户,并使用 asp.net mvc 在控制器中的请求上提供该用户。问题是当前框架不支持从操作过滤器执行异步操作。所以 OnActionExecuting,OnAuthorization 方法不允许我这样做..例如,我有以下代码不起作用(所以不要尝试)..你得到一个异常:“异步模块或处理程序在异步时完成操作仍在等待中。”

protected async override void OnAuthorization(AuthorizationContext filterContext)
{
  var user = filterContext.HttpContext.User;
  if (!user.Identity.IsAuthenticated)
  {
    HandleUnauthorizedRequest(filterContext);
    return;
  }

  using (var session = MvcApplication.DocumentStore.OpenAsyncSession())
  {
    User currentUser = await session.LoadAsync<User>(user.Identity.Name);
    if (currentUser == null)
    {
      HandleUnauthorizedRequest(filterContext);
      return;
    }

    filterContext.HttpContext.Items["User"] = currentUser;
  }
}

那么还有其他方法可以做到这一点吗?我注意到基础控制器中有一个开始执行方法:

protected override IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
{
  return base.BeginExecute(requestContext, callback, state);
}

我可以在那里做吗?

【问题讨论】:

标签: asp.net asp.net-mvc asynchronous ravendb


【解决方案1】:

这个问题已经三个月了,所以我想你已经设法解决了这个问题。无论如何,我将在此处添加我的解决方案,因为我必须做类似的事情。

我使用了ParallelExtensionsExtras 库中的ToAsync 方法。这是我的课:

public class AsyncControllerBase : Controller
{
    protected override IAsyncResult BeginExecute(System.Web.Routing.RequestContext requestContext, AsyncCallback callback, object state)
    {
        return ExecuteCoreAsync(requestContext, state).ToAsync(callback, state);
    }

    protected override void EndExecute(IAsyncResult asyncResult)
    {
        IAsyncResult baseAsyncResult = ((Task<IAsyncResult>)asyncResult).Result;
        base.EndExecute(baseAsyncResult);
    }

    protected virtual async Task<IAsyncResult> ExecuteCoreAsync(System.Web.Routing.RequestContext requestContext, object state)
    {
        await DoStuffHereOrInDerivedClassAsync();

        var baseBeginExecuteCompletion = new TaskCompletionSource<IAsyncResult>();

        AsyncCallback callback = ar =>
        {
            baseBeginExecuteCompletion.SetResult(ar);
        };

        // OnActionExecuting will be called at this point
        var baseAsyncResult = base.BeginExecute(requestContext, callback, state);

        await baseBeginExecuteCompletion.Task;

        return baseAsyncResult;
    }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
    }
}

另请参阅 Microsoft 的 this documentation,了解在 Task 和 IAsyncResult 之间进行转换。

【讨论】:

  • 请注意Controller.Request 和许多其他属性在nullDoStuffHereOrInDerivedClassAsync(),最好将RequestContext 作为参数传递以访问某些功能。
  • 为什么 OnActionExecuting 的“空”覆盖?
  • 嗨 Dirk,我写这篇文章已经两年半了,所以我真的不记得了:) 也许最初的意图是密封覆盖以避免派生混淆课程 - 但忘了实际做?!
  • 在 mvc 5.2.3 中仍然需要这样做。发现一个改进:覆盖(Begin|End)ExecuteCore而不是(Begin|End')Execute,那么你可以使用Controller.Request
猜你喜欢
  • 1970-01-01
  • 2011-03-20
  • 2017-05-30
  • 1970-01-01
  • 2017-06-23
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多