How to render an ASP.NET MVC view as a string?

后端 未结 15 2960
挽巷
挽巷 2020-11-21 04:40

I want to output two different views (one as a string that will be sent as an email), and the other the page displayed to a user.

Is this possible in ASP.NET MVC bet

相关标签:
15条回答
  • 2020-11-21 04:51

    you are get the view in string using this way

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

    We are call this method in two way

    string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", null)
    

    OR

    var model = new Person()
    string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", model)
    
    0 讨论(0)
  • 2020-11-21 04:52

    This article describes how to render a View to a string in different scenarios:

    1. MVC Controller calling another of its own ActionMethods
    2. MVC Controller calling an ActionMethod of another MVC Controller
    3. WebAPI Controller calling an ActionMethod of an MVC Controller

    The solution/code is provided as a class called ViewRenderer. It is part of Rick Stahl's WestwindToolkit at GitHub.

    Usage (3. - WebAPI example):

    string html = ViewRenderer.RenderView("~/Areas/ReportDetail/Views/ReportDetail/Index.cshtml", ReportVM.Create(id));
    
    0 讨论(0)
  • 2020-11-21 04:56

    This answer is not on my way . This is originally from https://stackoverflow.com/a/2759898/2318354 but here I have show the way to use it with "Static" Keyword to make it common for all Controllers .

    For that you have to make static class in class file . (Suppose your Class File Name is Utils.cs )

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

    Now you can call this class from your controller by adding NameSpace in your Controller File as following way by passing "this" as parameter to Controller.

    string result = RazorViewToString.RenderRazorViewToString(this ,"ViewName", model);
    

    As suggestion given by @Sergey this extension method can also call from cotroller as given below

    string result = this.RenderRazorViewToString("ViewName", model);
    

    I hope this will be useful to you make code clean and neat.

    0 讨论(0)
  • 2020-11-21 04:57

    If you want to forgo MVC entirely, thereby avoiding all the HttpContext mess...

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

    This uses the awesome open source Razor Engine here: https://github.com/Antaris/RazorEngine

    0 讨论(0)
  • 2020-11-21 05:01

    Quick tip

    For a strongly typed Model just add it to the ViewData.Model property before passing to RenderViewToString. e.g

    this.ViewData.Model = new OrderResultEmailViewModel(order);
    string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
    
    0 讨论(0)
  • 2020-11-21 05:01

    Here is a class I wrote to do this for ASP.NETCore RC2. I use it so I can generate html email using Razor.

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Abstractions;
    using Microsoft.AspNetCore.Mvc.ModelBinding;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.AspNetCore.Mvc.ViewEngines;
    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    using Microsoft.AspNetCore.Routing;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace cloudscribe.Web.Common.Razor
    {
        /// <summary>
        /// the goal of this class is to provide an easy way to produce an html string using 
        /// Razor templates and models, for use in generating html email.
        /// </summary>
        public class ViewRenderer
        {
            public ViewRenderer(
                ICompositeViewEngine viewEngine,
                ITempDataProvider tempDataProvider,
                IHttpContextAccessor contextAccesor)
            {
                this.viewEngine = viewEngine;
                this.tempDataProvider = tempDataProvider;
                this.contextAccesor = contextAccesor;
            }
    
            private ICompositeViewEngine viewEngine;
            private ITempDataProvider tempDataProvider;
            private IHttpContextAccessor contextAccesor;
    
            public async Task<string> RenderViewAsString<TModel>(string viewName, TModel model)
            {
    
                var viewData = new ViewDataDictionary<TModel>(
                            metadataProvider: new EmptyModelMetadataProvider(),
                            modelState: new ModelStateDictionary())
                {
                    Model = model
                };
    
                var actionContext = new ActionContext(contextAccesor.HttpContext, new RouteData(), new ActionDescriptor());
                var tempData = new TempDataDictionary(contextAccesor.HttpContext, tempDataProvider);
    
                using (StringWriter output = new StringWriter())
                {
    
                    ViewEngineResult viewResult = viewEngine.FindView(actionContext, viewName, true);
    
                    ViewContext viewContext = new ViewContext(
                        actionContext,
                        viewResult.View,
                        viewData,
                        tempData,
                        output,
                        new HtmlHelperOptions()
                    );
    
                    await viewResult.View.RenderAsync(viewContext);
    
                    return output.GetStringBuilder().ToString();
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题