Dan*_*son 473 asp.net-mvc rendering
我想输出两个不同的视图(一个作为将作为电子邮件发送的字符串),另一个显示给用户的页面.
这是否可以在ASP.NET MVC beta中使用?
我尝试过多个例子:
1. ASP.NET MVC Beta中的RenderPartial到String
如果我使用此示例,则会收到"在HTTP标头发送后无法重定向".
如果我使用它,我似乎无法执行redirectToAction,因为它尝试渲染可能不存在的视图.如果我确实返回了视图,那么它完全搞砸了,看起来根本不正确.
有没有人对我遇到的这些问题有任何想法/解决方案,或者对更好的问题有任何建议?
非常感谢!
以下是一个例子.我要做的是创建GetViewForEmail方法:
public ActionResult OrderResult(string ref)
{
//Get the order
Order order = OrderService.GetOrder(ref);
//The email helper would do the meat and veg by getting the view as a string
//Pass the control name (OrderResultEmail) and the model (order)
string emailView = GetViewForEmail("OrderResultEmail", order);
//Email the order out
EmailHelper(order, emailView);
return View("OrderResult", order);
}
Run Code Online (Sandbox Code Playgroud)
Tim Scott接受的答案(由我改变并格式化):
public virtual string RenderViewToString(
ControllerContext controllerContext,
string viewPath,
string masterPath,
ViewDataDictionary viewData,
TempDataDictionary tempData)
{
Stream filter = null;
ViewPage viewPage = new ViewPage();
//Right, create our view
viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);
//Get the response context, flush it and get the response filter.
var response = viewPage.ViewContext.HttpContext.Response;
response.Flush();
var oldFilter = response.Filter;
try
{
//Put a new filter into the response
filter = new MemoryStream();
response.Filter = filter;
//Now render the view into the memorystream and flush the response
viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
response.Flush();
//Now read the rendered view.
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
return reader.ReadToEnd();
}
finally
{
//Clean up.
if (filter != null)
{
filter.Dispose();
}
//Now replace the response filter
response.Filter = oldFilter;
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例
假设来自控制器的呼叫获取订单确认电子邮件,则传递Site.Master位置.
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
Run Code Online (Sandbox Code Playgroud)
Ben*_*esh 563
这就是我想出来的,它对我有用.我将以下方法添加到我的控制器基类中.(您可以随时将这些静态方法设置为接受控制器作为参数的其他地方)
MVC2 .ascx风格
protected string RenderViewToString<T>(string viewPath, T model) {
ViewData.Model = model;
using (var writer = new StringWriter()) {
var view = new WebFormView(ControllerContext, viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(ControllerContext, view, vdd,
new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
剃刀.cshtml风格
public string RenderRazorViewToString(string viewName, object model)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View,
ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:添加了Razor代码.
Dil*_*165 67
这个答案不在我的路上.这最初来自/sf/answers/193192891/, 但在这里我已经展示了将它与"静态"关键字一起使用的方法,使其适用于所有控制器.
为此,你必须static在类文件中创建类.(假设您的类文件名是Utils.cs)
这个例子是For Razor.
Utils.cs
public static class RazorViewToString
{
public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以通过将"this"作为参数传递给Controller,在控制器文件中添加NameSpace,从控制器调用此类.
string result = RazorViewToString.RenderRazorViewToString(this ,"ViewName", model);
Run Code Online (Sandbox Code Playgroud)
根据@Sergey给出的建议,这个扩展方法也可以从cotroller调用,如下所示
string result = this.RenderRazorViewToString("ViewName", model);
Run Code Online (Sandbox Code Playgroud)
我希望这对你使代码干净整洁有用.
Tim*_*ott 32
这对我有用:
public virtual string RenderView(ViewContext viewContext)
{
var response = viewContext.HttpContext.Response;
response.Flush();
var oldFilter = response.Filter;
Stream filter = null;
try
{
filter = new MemoryStream();
response.Filter = filter;
viewContext.View.Render(viewContext, viewContext.HttpContext.Response.Output);
response.Flush();
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
return reader.ReadToEnd();
}
finally
{
if (filter != null)
{
filter.Dispose();
}
response.Filter = oldFilter;
}
}
Run Code Online (Sandbox Code Playgroud)
Lor*_*zCK 29
我发现了一个新的解决方案,可以将视图呈现为字符串,而不必混淆当前HttpContext的响应流(它不允许您更改响应的ContentType或其他标头).
基本上,您所做的就是为视图创建一个假的HttpContext来呈现自己:
/// <summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
string viewName, object viewData) {
//Create memory writer
var sb = new StringBuilder();
var memWriter = new StringWriter(sb);
//Create fake http context to render the view
var fakeResponse = new HttpResponse(memWriter);
var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
var fakeControllerContext = new ControllerContext(
new HttpContextWrapper(fakeContext),
controller.ControllerContext.RouteData,
controller.ControllerContext.Controller);
var oldContext = HttpContext.Current;
HttpContext.Current = fakeContext;
//Use HtmlHelper to render partial view to fake context
var html = new HtmlHelper(new ViewContext(fakeControllerContext,
new FakeView(), new ViewDataDictionary(), new TempDataDictionary()),
new ViewPage());
html.RenderPartial(viewName, viewData);
//Restore context
HttpContext.Current = oldContext;
//Flush memory and return output
memWriter.Flush();
return sb.ToString();
}
/// <summary>Fake IView implementation used to instantiate an HtmlHelper.</summary>
public class FakeView : IView {
#region IView Members
public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
throw new NotImplementedException();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
这适用于ASP.NET MVC 1.0,以及ContentResult,JsonResult等.(更改原始HttpResponse上的Headers不会抛出" 服务器无法在发送HTTP标头后设置内容类型 "异常).
更新:在ASP.NET MVC 2.0 RC中,代码有所改变,因为我们必须传入StringWriter用于将视图写入ViewContext:
//...
//Use HtmlHelper to render partial view to fake context
var html = new HtmlHelper(
new ViewContext(fakeControllerContext, new FakeView(),
new ViewDataDictionary(), new TempDataDictionary(), memWriter),
new ViewPage());
html.RenderPartial(viewName, viewData);
//...
Run Code Online (Sandbox Code Playgroud)
Jen*_*lly 11
本文介绍如何在不同的方案中将视图呈现为字符串:
解决方案/代码作为名为ViewRenderer的类提供.它是Rick Stahl 在GitHub的WestwindToolkit的一部分.
用法(3. - WebAPI示例):
string html = ViewRenderer.RenderView("~/Areas/ReportDetail/Views/ReportDetail/Index.cshtml", ReportVM.Create(id));
Run Code Online (Sandbox Code Playgroud)
如果你想完全放弃MVC,从而避免所有的HttpContext混乱......
using RazorEngine;
using RazorEngine.Templating; // For extension methods.
string razorText = System.IO.File.ReadAllText(razorTemplateFileLocation);
string emailBody = Engine.Razor.RunCompile(razorText, "templateKey", typeof(Model), model);
Run Code Online (Sandbox Code Playgroud)
这里使用了很棒的开源Razor引擎:https: //github.com/Antaris/RazorEngine
ASP NET CORE 的附加提示:
界面:
public interface IViewRenderer
{
Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model);
}
Run Code Online (Sandbox Code Playgroud)
执行:
public class ViewRenderer : IViewRenderer
{
private readonly IRazorViewEngine viewEngine;
public ViewRenderer(IRazorViewEngine viewEngine) => this.viewEngine = viewEngine;
public async Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model)
{
ViewEngineResult viewEngineResult = this.viewEngine.FindView(controller.ControllerContext, name, false);
if (!viewEngineResult.Success)
{
throw new InvalidOperationException(string.Format("Could not find view: {0}", name));
}
IView view = viewEngineResult.View;
controller.ViewData.Model = model;
await using var writer = new StringWriter();
var viewContext = new ViewContext(
controller.ControllerContext,
view,
controller.ViewData,
controller.TempData,
writer,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return writer.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
注册 Startup.cs
...
services.AddSingleton<IViewRenderer, ViewRenderer>();
...
Run Code Online (Sandbox Code Playgroud)
以及在控制器中的用法:
public MyController: Controller
{
private readonly IViewRenderer renderer;
public MyController(IViewRendere renderer) => this.renderer = renderer;
public async Task<IActionResult> MyViewTest
{
var view = await this.renderer.RenderAsync(this, "MyView", model);
return new OkObjectResult(view);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
您将使用这种方式获取字符串视图
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
if (model != null)
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
我们以两种方式称呼此方法
string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", null)
Run Code Online (Sandbox Code Playgroud)
要么
var model = new Person()
string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", model)
Run Code Online (Sandbox Code Playgroud)
要将视图渲染到服务层中的字符串而不必传递 ControllerContext,这里有一篇很好的 Rick Strahl 文章http://www.codemag.com/Article/1312081,它创建了一个通用控制器。代码摘要如下:
// Some Static Class
public static string RenderViewToString(ControllerContext context, string viewPath, object model = null, bool partial = false)
{
// first find the ViewEngine for this view
ViewEngineResult viewEngineResult = null;
if (partial)
viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
else
viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
if (viewEngineResult == null)
throw new FileNotFoundException("View cannot be found.");
// get the view and attach the model to view data
var view = viewEngineResult.View;
context.Controller.ViewData.Model = model;
string result = null;
using (var sw = new StringWriter())
{
var ctx = new ViewContext(context, view, context.Controller.ViewData, context.Controller.TempData, sw);
view.Render(ctx, sw);
result = sw.ToString();
}
return result;
}
// In the Service Class
public class GenericController : Controller
{ }
public static T CreateController<T>(RouteData routeData = null) where T : Controller, new()
{
// create a disconnected controller instance
T controller = new T();
// get context wrapper from HttpContext if available
HttpContextBase wrapper;
if (System.Web.HttpContext.Current != null)
wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
else
throw new InvalidOperationException("Cannot create Controller Context if no active HttpContext instance is available.");
if (routeData == null)
routeData = new RouteData();
// add the controller routing if not existing
if (!routeData.Values.ContainsKey("controller") &&
!routeData.Values.ContainsKey("Controller"))
routeData.Values.Add("controller", controller.GetType().Name.ToLower().Replace("controller", ""));
controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
return controller;
}
Run Code Online (Sandbox Code Playgroud)
然后在服务类中呈现视图:
var stringView = RenderViewToString(CreateController<GenericController>().ControllerContext, "~/Path/To/View/Location/_viewName.cshtml", theViewModel, true);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
288281 次 |
| 最近记录: |