简体   繁体   English

在 ASP.NET Core 2.2 中将局部视图渲染为 HTML 字符串

[英]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) 这个答案的来源,他值得称赞(我在这里添加它是因为我需要类似的东西,我花了很长时间才找到它)

Defining the interface for the Dependency Inejection定义依赖注入的接口

public interface IViewRenderService
{
    Task<string> RenderToStringAsync(string viewName, object model);
}

The service's implementation服务的实现

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();
        }
    }
}

Adding the class in the ConfigureServices function:ConfigureServices函数中添加类:

services.AddScoped<IViewRenderService, ViewRenderService>();

Finally, Using the service最后,使用服务

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.

相关问题 ASP.NET Core 将包含部分视图的视图渲染为字符串 - ASP.NET Core Render a View with Partial Views inside to String 如何将位于应用程序部分 (DLL) 中的部分视图呈现到主 asp.net 核心 2.2 项目中 - How to render a partial view located in an application part (DLL) into main asp.net core 2.2 project 当部分视图包含渲染操作时,将ASP.Net MVC部分视图渲染为字符串 - Render an ASP.Net MVC partial view to a string when the partial view contains a render action 为导入的CSS和js asp.net core 2.2创建部分视图 - Create a partial view for the imports of css and js asp.net core 2.2 ASP.NET CORE 将 Razor 视图渲染为带有控制器参数的字符串 - ASP.NET CORE Render Razor View to string with controller parameters 如何在 ASP.NET CORE 1.1 中将视图呈现为字符串 - How to render View as String in ASP.NET CORE 1.1 在 ASP.NET Core 中将 Razor 视图渲染为字符串 - Render Razor View to string in ASP.NET Core ASP.NET Core 5 MVC 从视图中渲染字符串 - ASP.NET Core 5 MVC Render string from action in view 如何将ApplicationDbContext绑定到ASP.Net Core 2.2中的View - How to bind ApplicationDbContext to a View in ASP.Net Core 2.2 ASP.NET MVC Razor:如何在控制器动作中呈现Razor Partial View的HTML - ASP.NET MVC Razor: How to render a Razor Partial View's HTML inside the controller action
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM