这是在不阻止ASP.NET MVC中的请求的情况下在每个请求上添加数据的好方法吗?

时间:2012-06-26 23:44:20

标签: asp.net-mvc

我正在构建的MVC应用程序有一部分页面(实现为部分),它使用从ViewData加载的ViewModel。我创建了一个抽象控制器,我的所有控制器都继承了这个控制器(我正在使用的IoC系统使基本控制器成为最佳选择)。目前,我正在OnActionExecuting覆盖中设置数据。

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    ViewData["OperationStatusVM"] = OperationsStatusBuilder.Get(Operations);
    base.OnActionExecuting(filterContext);
}

问题是OperationsStatusBuilder方法运行得相当长。我正在尝试整合一种方法来填充ViewModel而不会阻止其余的请求。

我的第一个想法是通过OnActionExecuting中的Task启动操作,然后在OnActionExecuted中设置实际值。

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    filterContext.RequestContext.HttpContext.Items["OperationTask"]
        = Task<OperationsStatusVM>.Factory.StartNew(() => OperationsStatusBuilder.Get(Operations));
    base.OnActionExecuting(filterContext);
}

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var task = filterContext.RequestContext.HttpContext.Items["OperationTask"] as Task<OperationsStatusVM>;
    ViewData["OperationStatusVM"] = task.Result;
    base.OnActionExecuted(filterContext);
}

我仍然在解决问题,但似乎我可能错过了使用内置于MVC中的东西的机会。我的主要要求是在呈现页面时必须设置ViewData

这种方法有意义吗?这是解决这个问题的好方法,还是有更好的方法?

谢谢, 埃里克

2 个答案:

答案 0 :(得分:1)

听起来你在MVC中描述了异步控制器?虽然这会释放IIS以便在处理长时间运行的请求时响应其他请求,但如果您希望在执行OperationsStatusBuilder时同一个Action中的其他方法运行,则必须使用某些异步代码提示它们并等待让所有人在将结果返回到要渲染的视图之前返回结果。如果您在托管此站点的服务器上有多个核心,则会看到最佳结果。这是我在应用程序中使用的一个示例,用于异步地从数据库中提取文档。

GetFileResult方法(在我的控制器中被标记为非操作)是实际运行我的逻辑的。我将任务传递回结果的原因是Async方法中引发的错误从未进入结果方法。通过将任务作为参数传递并调用task.Wait()作为我的结果方法的第一行,我能够使它重新抛出异常并让网站处理/显示而不是默默地忽略它们。

请注意,如果您有多个长时间运行的任务可以同时运行,则可以创建多个任务,并为每个任务增加一次OutstandingOperations。只有当未完成的操作数达到0并且它们都已完成时,您的结果才会得到结果。

public void FileAsync(Guid id)
{
    AsyncManager.OutstandingOperations.Increment();
    Action getFileAsync = () =>
        {
            FileResult fileResult = GetFileResult(id, false);
            AsyncManager.Parameters["result"] = fileResult;
            AsyncManager.OutstandingOperations.Decrement();
        };
    var task = Task.Factory.StartNew(getFileAsync);
    AsyncManager.Parameters["task"] = task;
}
public ActionResult FileCompleted(FileResult result, Task task)
{
    task.Wait(); 
    if (result == null)
        return HttpNotFound();
    return result;
}

答案 1 :(得分:0)

  

“问题是OperationsStatusBuilder方法运行得相当长。我正在尝试&gt;组合一种方法来填充ViewModel而不会阻塞其余的   请求“。

这是一个请求。因为客户端将视图+部分视图的合并结果作为一个文档获取。你所描述的做什么听起来像一个插座。无论如何,我认为唯一的方法是向下发送页面,然后在事后使用AJAX请求部分视图并更新页面。

或者我感到困惑?

<强>此外:

您不必在ViewData字典中存储部分视图模型。您可以将其存储在主模型中,然后像下面这样调用您的部分:@Html.Partial(Model.MyPartialViewModel)