4 回答
TA贡献1874条经验 获得超12个赞
控制器扩展实现
public static class ControllerExtensions
{
/// <summary>
/// Render a partial view to string.
/// </summary>
public static async Task<string> RenderViewToStringAsync(this Controller controller, string viewNamePath, object model = null)
{
if (string.IsNullOrEmpty(viewNamePath))
viewNamePath = controller.ControllerContext.ActionDescriptor.ActionName;
controller.ViewData.Model = model;
using (StringWriter writer = new StringWriter())
{
try
{
var view = FindView(controller, viewNamePath);
ViewContext viewContext = new ViewContext(
controller.ControllerContext,
view,
controller.ViewData,
controller.TempData,
writer,
new HtmlHelperOptions()
);
await view.RenderAsync(viewContext);
return writer.GetStringBuilder().ToString();
}
catch (Exception exc)
{
return $"Failed - {exc.Message}";
}
}
}
private static IView FindView(Controller controller, string viewNamePath)
{
IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
ViewEngineResult viewResult = null;
if (viewNamePath.EndsWith(".cshtml"))
viewResult = viewEngine.GetView(viewNamePath, viewNamePath, false);
else
viewResult = viewEngine.FindView(controller.ControllerContext, viewNamePath, false);
if (!viewResult.Success)
{
var endPointDisplay = controller.HttpContext.GetEndpoint().DisplayName;
if (endPointDisplay.Contains(".Areas."))
{
//search in Areas
var areaName = endPointDisplay.Substring(endPointDisplay.IndexOf(".Areas.") + ".Areas.".Length);
areaName = areaName.Substring(0, areaName.IndexOf(".Controllers."));
viewNamePath = $"~/Areas/{areaName}/views/{controller.HttpContext.Request.RouteValues["controller"]}/{controller.HttpContext.Request.RouteValues["action"]}.cshtml";
viewResult = viewEngine.GetView(viewNamePath, viewNamePath, false);
}
if (!viewResult.Success)
throw new Exception($"A view with the name '{viewNamePath}' could not be found");
}
return viewResult.View;
}
}
控制器操作中的用法:
var html = await this.RenderViewToStringAsync("actionName" , model);
TA贡献1816条经验 获得超6个赞
可以使用服务从任何位置(控制器,页面模型等)获取部分视图(或多个):
这个答案的起源,他值得称赞(我在这里添加它,因为我需要这样的东西,我花了很长时间才找到它)
定义依赖关系插入的接口
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
服务的实现
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
在函数中添加类:ConfigureServices
services.AddScoped<IViewRenderService, ViewRenderService>();
最后,使用服务
string html = await m_RenderService.RenderToStringAsync("<NameOfPartial>", new Model());
TA贡献1798条经验 获得超7个赞
为什么 Json 结果带有 html 字符串?您可以直接返回分部视图以返回 html。
public IActionResult GetUpsertPartialView(MessageBoard messageBoard)
{
return PartialView("someviewname", messageBoard);
}
TA贡献1806条经验 获得超5个赞
扩展Aharon的答案,它解决了OP的“纯”标题问题,即如何将部分呈现为字符串,我在下面添加了我自己的解决方案。我的是直接从控制器操作中执行此操作。
当然,OP不应该在他们的用例中使用它,因为例外的答案是正确的。
该方法是您自己的。CreateViewModelAsync
// SomeController.cs
public SomeController(
IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine,
IModelMetadataProvider metadataProvider, IViewBufferScope bufferScope,
HtmlEncoder htmlEncoder, UrlEncoder urlEncoder,
ModelExpressionProvider modelExpressionProvider)
{
this.viewEngine = viewEngine;
this.cardHtmlHelper = new HtmlHelper<TimesheetCardModel>(
htmlGenerator, viewEngine, metadataProvider, bufferScope,
htmlEncoder, urlEncoder, modelExpressionProvider);
}
[HttpGet]
[Route("test", Name = "TestRoute")]
public async Task<IActionResult> GetTest()
{
// Example renders a partial view as HTML using MotherModel.Children.First() as
// the model for the partial.
MotherModel viewModel = await this.CreateViewModelAsync();
const string viewName = "_MyPartial";
var foundView = this.viewEngine.FindView(this.ControllerContext, viewName, false);
var viewData = new ViewDataDictionary<FirstChildModel>(this.ViewData);
var textWriter = new StringWriter();
var viewContext = new ViewContext(this.ControllerContext, foundView.View, viewData, this.TempData, textWriter, new HtmlHelperOptions());
this.cardHtmlHelper.Contextualize(viewContext);
var htmlContent = await this.cardHtmlHelper.PartialAsync(viewName, pageModel.Children.First(), viewData);
htmlContent.WriteTo(textWriter, HtmlEncoder.Default);
var html = textWriter.ToString();
...
}
- 4 回答
- 0 关注
- 65 浏览
添加回答
举报