2016-09-05 3 views
1

У меня есть ASP.NET MVC-контроллер с кучей методов действий, возвращающих ViewResult. Теперь, мне нужно, чтобы иметь возможность изменить результат действий на основе определенного параметра URL следующим образом:ASP.NET MVC - изменение результата отображения в OnActionExecuted

  • Если параметр не присутствует, просто вернуть ViewResult как это
  • , если параметр присутствует, возьмите ViewResult от действий, который был только выполнен, визуализации представления в строку и возвращает FileStreamResult, содержащий эту строку (сырой HTML) + некоторая дополнительная информация (не относится к вопросу)

I Я попытался сделать это, переопределив 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 здесь.

Как я могу визуализировать представление в строке здесь?

+0

почему вы не просто возвращать строку из вашего ActionResult? –

+0

@JordyvanEijk, потому что у меня много действий в контроллере, для которого мне нужно реализовать ту же логику. Я хочу, чтобы все это одним способом. –

+0

Взгляните на [этот вопрос SO] (http://stackoverflow.com/questions/553936/in-mvc-how-do-return-a-string-result) –

ответ

1

viewResult.View заполняется только в том случае, если результат просмотра выполнен в контексте контроллера (см. Метод ExecuteResult в MVC source code). Метод 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(); 
    } 
}