0

我正在构建的 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。

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

谢谢,埃里克

4

2 回答 2

1

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

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

请注意,如果您有多个长时间运行的任务以让它们同时运行,您可以创建多个任务,并为每个任务增加一次未完成操作。只有当未完成的操作数达到 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;
}
于 2012-06-27T00:36:07.243 回答
0

“问题是 OperationsStatusBuilder 方法运行时间相当长。我正在尝试 > 组合一种方法来填充 ViewModel 而不会阻塞请求的其余部分。”

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

还是我很困惑?

此外:

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

于 2012-06-26T23:48:33.750 回答