Andre Borges Andre Borges - 4 months ago 57
C# Question

ASP.NET MVC - Modifying view result in OnActionExecuted

I have a ASP.NET MVC controller with a bunch of action methods returning ViewResult. Now, I need to be able to change the result of the action based on a certain URL parameter in the following way:

  • If the parameter is not present, just return the
    as it is

  • If the parameter is present, take the
    from the action that was just executed, render the view into a string, and return
    containing this string (raw HTML) + some additional info (not relevant for the question)

I've tried to do this by overriding
in my controller:

protected override void OnActionExecuted(ActionExecutedContext 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");

But I can't find a way to implement
, because for some reason

How can I render the view into a string here?


viewResult.View is filled only when the view result is executed in the context of a controller (see ExecuteResult method in MVC source code). The method OnActionExecuted is called earlier in the pipeline, that's why viewResult.View is null in your case.

What you need to do is manually find the view using ViewEngineCollection and then render it:

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