MVC 5 Render View to String
Кажется, что большинство кода для представления представления в строку не работает в MVC 5.
У меня есть последние шаблоны MVC 5.1.2, и я пытаюсь отобразить представление в строке.
public static String RenderViewToString(ControllerContext context, String viewPath, object model = null)
{
context.Controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindView(context, viewPath, null);
var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(context, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Ну, он работает, но его вывод содержит много меток вместо меток. Я читал что-то об этом было исправлено в версии RC, но это старые новости.
Проблема выглядит так:
<$A$><h1></h1>
<table</$A$><$B$> class=""</$B$><$C$>> <tbody</$C$><$D$></$D$><$E$>></tbody>
</table></$E$>
Я хотел бы спросить, как вы визуализируете представления в строку в последнем шаблоне MVC 5?
Спасибо.
Ответы
Ответ 1
Хорошо, кажется, я нашел решение. Автор идеи - Якирское поместье.
class FakeController : ControllerBase
{
protected override void ExecuteCore() { }
public static string RenderViewToString(string controllerName, string viewName, object viewData)
{
using (var writer = new StringWriter())
{
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
}
Это трюк с фальшивым контекстом и ответом.
Пример:
String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );
Мой файл MyHTMLView.cstml хранится в Views/Email/MyHTMLView.cshtml. Электронная почта - это имя поддельного контроллера.
Ответ 2
Ниже приведено решение, которое работает с сеансом и областями на MVC5.
public class FakeController : ControllerBase
{
protected override void ExecuteCore() { }
public static string RenderViewToString(string controllerName, string viewName,string areaName, object viewData,RequestContext rctx)
{
try
{
using (var writer = new StringWriter())
{
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
routeData.Values.Add("Area", areaName);
routeData.DataTokens["area"] = areaName;
var fakeControllerContext = new ControllerContext(rctx, new FakeController());
//new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
fakeControllerContext.RouteData = routeData;
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.GetStringBuilder().ToString();
//use example
//String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );
//where file MyHTMLView.cstml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name.
}
}
catch (Exception ex)
{
//do your exception handling here
}
}
}
вот как вы это называете от другого контроллера
var modal = getModal(params);
return FakeController.RenderViewToString(controllerName, viewName, areaName, modal, this.Request.RequestContext);
используя requestcontext, мы можем легко передать текущий сеанс в fakecontroller и визуализировать строку бритвы.
Ответ 3
Мне сразу потребовалось вернуть 6 частичных представлений в виде строк в объекте JSON. Вместо того, чтобы создавать статический метод и передавать все ненужные параметры, я решил добавить защищенные методы к нашему классу ControllerBase, который происходит от Controller, и используется как базовый класс для всех наших контроллеров.
Вот полнофункциональный класс ControllerBase, который предоставляет эту функциональность и очень похож на методы PartialView() и View(), которые находятся в классе Controller. Он включает дополнения от @Alok.
public abstract class ControllerBase : Controller
{
#region PartialViewToString
protected string PartialViewToString(string partialViewName, object model = null)
{
ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this);
return ViewToString(
controllerContext,
ViewEngines.Engines.FindPartialView(controllerContext, partialViewName) ?? throw new FileNotFoundException("Partial view cannot be found."),
model
);
}
#endregion
#region ViewToString
protected string ViewToString(string viewName, object model = null)
{
ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this);
return ViewToString(
controllerContext,
ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."),
model
);
}
protected string ViewToString(string viewName, string controllerName, string areaName, object model = null)
{
RouteData routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
if (areaName != null)
{
routeData.Values.Add("Area", areaName);
routeData.DataTokens["area"] = areaName;
}
ControllerContext controllerContext = new ControllerContext(HttpContext, routeData, this);
return ViewToString(
controllerContext,
ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."),
model
);
}
#endregion
#region Private Methods
private string ViewToString(ControllerContext controllerContext, ViewEngineResult viewEngineResult, object model)
{
using (StringWriter writer = new StringWriter())
{
ViewContext viewContext = new ViewContext(
ControllerContext,
viewEngineResult.View,
new ViewDataDictionary(model),
new TempDataDictionary(),
writer
);
viewEngineResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
#endregion
}
Ответ 4
@wh1sp3r ответ работает, но для частичных просмотров мне пришлось сделать следующие незначительные изменения:
string html = FakeController.RenderViewToString("**Controllername**", "~/views/**Controllername**/_AsdfPartialPage.cshtml", fem);
public static string RenderViewToString(string controllerName, string viewName, object viewData)
{
using (var writer = new StringWriter())
{
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null))), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
//var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var razorViewResult = razorViewEngine.FindPartialView(fakeControllerContext, viewName, false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
Ответ 5
Чтобы отобразить PartialView в строку, используйте этот код:
class FakeController: ControllerBase {
protected override void ExecuteCore() { }
public static string RenderViewToString(string controllerName, string viewName, object model) {
using(var writer = new StringWriter()) {
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null))), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindPartialView(fakeControllerContext, viewName, false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(model), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
}