[英]Render Partial View to HTML string in ASP.NET Core 2.2
I am trying to use AJAX to call my Controller and return a Partial View with a model as a string so that I can inject it into my HTML.我正在尝试使用 AJAX 来调用我的控制器并返回一个带有模型作为字符串的局部视图,以便我可以将它注入到我的 HTML 中。 I have done this before in MVC5 using a controller interface, but I can't seem to find anything on how to do this for a Partial View in Asp.Net Core 2.2.
我之前在 MVC5 中使用控制器接口完成了此操作,但我似乎无法找到有关如何为 Asp.Net Core 2.2 中的部分视图执行此操作的任何信息。 I have found examples of how to render a View to a string, but I could not modify them to work for a partial view.
我找到了如何将视图呈现为字符串的示例,但我无法修改它们以适用于局部视图。
Controller Action:控制器动作:
public JsonResult GetUpsertPartialView(MessageBoard messageBoard)
{
Dictionary<string, string> result = new Dictionary<string, string>();
string errorState = "0";
string errorMessage = "";
try
{
result["view"] = ""; // My call to render the Partial View would go here.
}
catch (Exception)
{
errorState = "1";
errorMessage = "An error was encountered while constructing the View.";
}
result["errorState"] = errorState;
result["errorMessage"] = errorMessage;
return Json(result);
}
AJAX Call: AJAX 调用:
$.ajax({
type: "GET",
url: "../Home/GetUpsertPartialView/",
data: messageBoardData,
contentType: 'application/json; charset=utf-8',
success: function (data) {
console.log(data);
$("#messageBoardModalBody").val(data.view);
$("#messageBoardModal").modal("show");
}
});
I've confirmed that my Controller is being hit, the parameters are being passed correctly, and I'm receiving the correct data back from the Action to my AJAX call.我已经确认我的控制器正在被命中,参数被正确传递,并且我正在从 Action 接收到正确的数据返回到我的 AJAX 调用。 The only thing I'm missing is the ability to render a Partial View directly to a string.
我唯一缺少的是将局部视图直接渲染为字符串的能力。
If there is another way to do this in Asp.net Core, I'm open to other options.如果在 Asp.net Core 中有另一种方法可以做到这一点,我愿意接受其他选择。
Note: I'm just doing this to learn Asp.Net Core.注意:我这样做只是为了学习 Asp.Net Core。 Please let me know if any more information is needed.
如果需要更多信息,请告诉我。
It is possible to get a partial view's (or several) from any where (a controller, page model etc) using a service:可以使用服务从任何位置(控制器、页面模型等)获取部分视图(或多个):
The Origin of this answer , he deserves the credit (I'm adding it here because I needed something like that and it took me quite a while to find it) 这个答案的来源,他值得称赞(我在这里添加它是因为我需要类似的东西,我花了很长时间才找到它)
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
function:ConfigureServices
函数中添加类:services.AddScoped<IViewRenderService, ViewRenderService>();
string html = await m_RenderService.RenderToStringAsync("<NameOfPartial>", new Model());
The ControllerExtensions implementation ControllerExtensions 实现
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;
}
}
Usage in your controller actions:在您的控制器操作中使用:
var html = await this.RenderViewToStringAsync("actionName" , model);
Why Json result with html string?为什么 Json 结果带有 html 字符串? You can return a partial view directly to return html.
可以直接返回局部视图返回html。
public IActionResult GetUpsertPartialView(MessageBoard messageBoard)
{
return PartialView("someviewname", messageBoard);
}
Expanding on Aharon's answer, which addresses the OP's "pure" title question of how to render a partial as a string, I'm adding my own solution below.扩展 Aharon 的答案,它解决了 OP 的“纯”标题问题,即如何将部分呈现为字符串,我在下面添加了我自己的解决方案。 Mine is to do this straight from with a controller action.
我的是直接从控制器动作中做到这一点。
Of course, the OP shouldn't use this in their use-case as the excepted answer is correct.当然,OP 不应该在他们的用例中使用它,因为例外答案是正确的。
The CreateViewModelAsync
method is your own. 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();
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.