ASP.NET MVC - 在OnActionExecuted中修改视图结果

时间:2016-09-05 14:06:11

标签: c# asp.net-mvc

我有一个ASP.NET MVC控制器,其中包含许多返回ViewResult的操作方法。现在,我需要能够通过以下方式根据某个URL参数更改操作的结果:

  • 如果参数不存在,只需按原样返回ViewResult
  • 如果参数存在,请从刚刚执行的操作中取出ViewResult,将视图渲染为字符串,然后返回包含此字符串的FileStreamResult(原始HTML)+一些其他信息(与问题无关)

我试图通过覆盖控制器中的OnActionExecuted来做到这一点:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    base.OnActionExecuted(filterContext);
    var viewResult = filterContext.Result as ViewResult;
    if (viewResult != null /* && certain URL param present*/)
    {
        string rawHtml = RenderViewIntoString(viewResult);
        filterContext.Result = new FileStreamResult(new MemoryStream(Encoding.UTF8.GetBytes(rawHtml)), "application/octet-stream");
    }
}

但是我无法找到实施RenderViewIntoString的方法,因为出于某种原因,viewResult.View在这里null

如何在此处将视图渲染为字符串?

1 个答案:

答案 0 :(得分:2)

只有在控制器的上下文中执行视图结果时才会填充

viewResult.View(请参阅MVC source code中的ExecuteResult方法)。方法OnActionExecuted在流程管理系统的前面调用,这就是为什么viewResult.View在您的情况下为null

您需要做的是使用ViewEngineCollection手动查找视图,然后呈现它:

private static string RenderViewIntoString(ViewResult viewResult, ActionExecutedContext filterContext)
{
    string viewName = !string.IsNullOrEmpty(viewResult.ViewName) ? viewResult.ViewName : filterContext.ActionDescriptor.ActionName;

    IView view = viewResult.ViewEngineCollection.FindView(filterContext.Controller.ControllerContext, viewName, viewResult.MasterName).View;

    if (view == null)
    {
        throw new InvalidOperationException($"The view '{viewName}' or its master was not found");
    }

    using (var stringWriter = new StringWriter())
    {
        var viewContext = new ViewContext(filterContext.Controller.ControllerContext, view, filterContext.Controller.ViewData, filterContext.Controller.TempData, stringWriter);
        view.Render(viewContext, stringWriter);
        return stringWriter.ToString();
    }
}