MVC 5 Render View to String

后端 未结 5 984
梦谈多话
梦谈多话 2020-12-13 09:44

It seems, most code for rendering view into string doesn\'t work in MVC 5.

I have latest MVC 5.1.2 templates and I am trying to render view into string.



        
相关标签:
5条回答
  • 2020-12-13 10:23

    following is the solution that works with session and areas on MVC5.

    public class FakeController : ControllerBase
    {
        protected override void ExecuteCore() { }
        public static string RenderViewToString(string controllerName, string viewName,string areaName, object viewData,RequestContext rctx)
        {
            try
            {
                using (var writer = new StringWriter())
                {
                    var routeData = new RouteData();
                    routeData.Values.Add("controller", controllerName);
                    routeData.Values.Add("Area", areaName);
                    routeData.DataTokens["area"] = areaName;
    
                    var fakeControllerContext = new ControllerContext(rctx, new FakeController());
                    //new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
                    fakeControllerContext.RouteData = routeData;
    
                    var razorViewEngine = new RazorViewEngine();
    
                    var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
    
                    var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
    
                    razorViewResult.View.Render(viewContext, writer);
                    return writer.GetStringBuilder().ToString();
                    //use example
                    //String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );
                    //where file MyHTMLView.cstml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name.
                }
            }
            catch (Exception ex)
            {
                //do your exception handling here
            }
        }
    }
    

    here is how you call this from another controller

    var modal = getModal(params);
    return FakeController.RenderViewToString(controllerName, viewName, areaName, modal, this.Request.RequestContext);
    

    using requestcontext we can easily pass current session in fakecontroller and render razor string.

    0 讨论(0)
  • 2020-12-13 10:25

    Ok, seems I found a solution. Author of the idea is Yakir Manor.

    class FakeController : ControllerBase
    {
        protected override void ExecuteCore() { }
        public static string RenderViewToString(string controllerName, string viewName, object viewData)
        {
            using (var writer = new StringWriter())
            {
                var routeData = new RouteData();
                routeData.Values.Add("controller", controllerName);
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
                var razorViewEngine = new RazorViewEngine();
                var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
    
                var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
                razorViewResult.View.Render(viewContext, writer);
                return writer.ToString();
    
            }
        }
    }
    

    It's a trick with fake context and response.

    Example:

    String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );
    

    My file MyHTMLView.cstml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name.

    0 讨论(0)
  • 2020-12-13 10:25

    @wh1sp3r answer works but for partial views I had to do the following minor changes:

     string html = FakeController.RenderViewToString("**Controllername**", "~/views/**Controllername**/_AsdfPartialPage.cshtml", fem);
    
    
    public static string RenderViewToString(string controllerName, string viewName, object viewData)
        {
            using (var writer = new StringWriter())
            {
                var routeData = new RouteData();
                routeData.Values.Add("controller", controllerName);
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null))), routeData, new FakeController());
                var razorViewEngine = new RazorViewEngine();
                //var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
    
                var razorViewResult = razorViewEngine.FindPartialView(fakeControllerContext, viewName,  false);
    
                var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
                razorViewResult.View.Render(viewContext, writer);
                return writer.ToString();
    
            }
        }
    
    0 讨论(0)
  • 2020-12-13 10:32

    To render PartialView to string use this code:

    class FakeController: ControllerBase {
        protected override void ExecuteCore() { }
        public static string RenderViewToString(string controllerName, string viewName, object model) {
            using(var writer = new StringWriter()) {
                var routeData = new RouteData();
                routeData.Values.Add("controller", controllerName);
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null))), routeData, new FakeController());
                var razorViewEngine = new RazorViewEngine();
                var razorViewResult = razorViewEngine.FindPartialView(fakeControllerContext, viewName, false);
                var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(model), new TempDataDictionary(), writer);
                razorViewResult.View.Render(viewContext, writer);
                return writer.ToString();
    
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 10:46

    I had an immediate need to return 6 partial views as strings in a JSON object. Instead of creating a static method, and passing all the unneeded parameters, I decided to add protected methods to our ControllerBase class that derives from Controller, and is used as the base class for all of our controllers.

    Here is a fully functional ControllerBase class that provides this functionality, and works very similar to the PartialView() and View() methods that are in the Controller class. It includes the additions from @Alok.

    public abstract class ControllerBase : Controller
    {
        #region PartialViewToString
    
        protected string PartialViewToString(string partialViewName, object model = null)
        {
            ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this);
    
            return ViewToString(
                controllerContext,
                ViewEngines.Engines.FindPartialView(controllerContext, partialViewName) ?? throw new FileNotFoundException("Partial view cannot be found."),
                model
            );
        }
    
        #endregion
    
        #region ViewToString
    
        protected string ViewToString(string viewName, object model = null)
        {
            ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this);
    
            return ViewToString(
                controllerContext,
                ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."),
                model
            );
        }
    
        protected string ViewToString(string viewName, string controllerName, string areaName, object model = null)
        {
            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", controllerName);
    
            if (areaName != null)
            {
                routeData.Values.Add("Area", areaName);
                routeData.DataTokens["area"] = areaName;
            }
    
            ControllerContext controllerContext = new ControllerContext(HttpContext, routeData, this);
    
            return ViewToString(
                controllerContext,
                ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."),
                model
            );
        }
    
        #endregion
    
        #region Private Methods
    
        private string ViewToString(ControllerContext controllerContext, ViewEngineResult viewEngineResult, object model)
        {
            using (StringWriter writer = new StringWriter())
            {
                ViewContext viewContext = new ViewContext(
                    controllerContext,
                    viewEngineResult.View,
                    new ViewDataDictionary(model),
                    new TempDataDictionary(),
                    writer
                );
    
                viewEngineResult.View.Render(viewContext, writer);
    
                return writer.ToString();
            }
        }
    
        #endregion
    }
    
    0 讨论(0)
提交回复
热议问题