Получить html из представления MVC 4 в строку

Я пытаюсь использовать принятый ответ из этого вопроса.

Кажется, что это будет именно то, что я ищу, но у меня проблема. Я не знаю, как это назвать. Это то, что я до сих пор:

Сначала я копирую код из упомянутого решения:

public string ToHtml(string viewToRender, ViewDataDictionary viewData, ControllerContext controllerContext)
{
    var result = ViewEngines.Engines.FindView(controllerContext, viewToRender, null);

    StringWriter output;
    using (output = new StringWriter())
    {
        var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output);
        result.View.Render(viewContext, output);
        result.ViewEngine.ReleaseView(controllerContext, result.View);
    }

    return output.ToString();
}

Это то, что у меня есть:

string viewToRender = "...";
int Data1 = ...;
int Data2 = ...;

System.Web.Mvc.ViewDataDictionary viewData = new System.Web.Mvc.ViewDataDictionary();
viewData.Add("Data1",Data1);
viewData.Add("Data2",Data2);

string html = ToHtml(viewToRender, viewData, ?????)//Here is my problem.

Что мне нужно передать в параметре controllerContext?

Ответы

Ответ 1

Вы можете создать базовый контроллер, который, очевидно, расширяет контроллер и использует вышеуказанную функцию в базовом контроллере, а другой контроллер, который расширяет этот базовый контроллер, сможет его использовать. Однако ControllerContext должен использоваться как

Request.RequestContext

И поэтому ваш BaseController будет похож на

public class BaseController: Controller
{
//your function here
}

И ваша функция ToHtml() будет

protected virtual string ToHtml(string viewToRender, ViewDataDictionary viewData )
{
   var controllerContext=Request.RequestContext;
   var result = ViewEngines.Engines.FindView(controllerContext, viewToRender, null);

   StringWriter output;
   using (output = new StringWriter())
   {
      var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output);
      result.View.Render(viewContext, output);
      result.ViewEngine.ReleaseView(controllerContext, result.View);
   }

   return output.ToString();
}

И при использовании базового контроллера

public class MyController: BaseController
{
//ToHtml(...);
}

Ответ 2

Вместо того, чтобы наследовать Controller, что означает, что вы должны помнить об этом каждый раз, или наследовать от CustomControllerBase, что означает, что вы должны помнить, чтобы наследовать каждый раз - просто создайте метод расширения:

public static class ControllerExtensions
{
    public static string RenderView(this Controller controller, string viewName, object model)
    {
        return RenderView(controller, viewName, new ViewDataDictionary(model));
    }

    public static string RenderView(this Controller controller, string viewName, ViewDataDictionary viewData)
    {
        var controllerContext = controller.ControllerContext;

        var viewResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);

        StringWriter stringWriter;

        using (stringWriter = new StringWriter())
        {
            var viewContext = new ViewContext(
                controllerContext,
                viewResult.View,
                viewData,
                controllerContext.Controller.TempData,
                stringWriter);

            viewResult.View.Render(viewContext, stringWriter);
            viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
        }

        return stringWriter.ToString();
    }
}

Затем в вашем Controller вы можете вызвать вот так:

this.RenderView("ViewName", model);

Ответ 3

Это скорее копия сообщения dav_i, за исключением того, что у вас есть модель с сильной типизацией, а также возможность создания частичных представлений:

Вместо того, чтобы наследовать Controller, что означает, что вы должны помнить об этом каждый раз, или наследовать от CustomControllerBase, что означает, что вы должны помнить, чтобы наследовать каждый раз - просто создайте метод расширения:

public static class ControllerExtensions
{
    public static string RenderView<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
    {
        var controllerContext = controller.ControllerContext;
        controllerContext.Controller.ViewData.Model = model;

        // To be or not to be (partial)
        var viewResult = partial ? ViewEngines.Engines.FindPartialView(controllerContext, viewName) : ViewEngines.Engines.FindView(controllerContext, viewName, null);

        StringWriter stringWriter;

        using (stringWriter = new StringWriter())
        {
            var viewContext = new ViewContext(
                controllerContext,
                viewResult.View,
                controllerContext.Controller.ViewData,
                controllerContext.Controller.TempData,
                stringWriter);

            viewResult.View.Render(viewContext, stringWriter);
            viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
        }

        return stringWriter.ToString();
    }
}

Затем в вашем Controller вы можете вызвать это (для полного просмотра):

this.RenderView("ViewName", model);

Это означает, что вы также получите doctype и элемент HTML и т.д. Для частичного просмотра используйте:

this.RenderView("ViewName", model, true);