Rendering a view on-the-fly

2019-04-12 06:38发布

I'm developing an ASP.NET MVC application that will send the user a confirmation email. For the email itself, I'd like to create a view and then render that view and send it using the .NET mail objects.

How can I do this using the MVC framework?

3条回答
欢心
2楼-- · 2019-04-12 07:29

You basically need to use IView.Render. You can get the view by using ViewEngineCollection.FindView (ViewEngines.Engines.FindView for the defaults). Render the output to a TextWriter and make sure you call ViewEngine.ReleaseView afterwards. Sample code below (untested):

StringWriter output = new StringWriter();

string viewName = "Email";
string masterName = "";

ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, viewName, masterName);

ViewContext viewContext = new ViewContext(ControllerContext, result.View, viewData, tempData);
result.View.Render(viewContext, output);

result.ViewEngine.ReleaseView(ControllerContext, result.View);

string viewOutput = output.ToString();

I'll leave viewData / tempData to you.

查看更多
SAY GOODBYE
3楼-- · 2019-04-12 07:40

This worked for me:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace Profiteer.WebUI.Controllers
{
    public class SampleController : Controller
    {
        public ActionResult Index()
        {
            RenderViewAsHtml(RouteData.Values["controller"].ToString(), 
                             RouteData.Values["action"].ToString());
            return View();
        }

        private void RenderViewAsHtml(string controllerName, string viewName)
        {
            var vEngine = (from ve in ViewEngineCollection
                           where ve.GetType() == typeof(RazorViewEngine)
                           select ve).FirstOrDefault();
            if (vEngine != null)
            {
                var view = 
                    vEngine.FindView(
                        ControllerContext, 
                        viewName, "_Layout", false).View as RazorView;
                if (view != null)
                {
                    var outPath = 
                       Server.MapPath(
                          string.Format("~/Views/{0}/{1}.html", 
                                        controllerName, viewName));
                    using (var sw = new StreamWriter(outPath, false))
                    {
                        var viewContext = 
                            new ViewContext(ControllerContext, 
                                            view, 
                                            new ViewDataDictionary(), 
                                            new TempDataDictionary(), 
                                            sw);
                        view.Render(viewContext, sw);
                    }
                }
            }
        }
    }
}
查看更多
可以哭但决不认输i
4楼-- · 2019-04-12 07:42

As per my comment on Richard's answer, this code did work, but it always resulted in a 'Cannot redirect after HTTP headers have been sent' error.

After a lot of digging around Google and being frustrated, I finally found some code that seems to do the trick, on this article:

http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

This guy's method is to create his own HttpContext.

Rather than use the MVCContrib BlockRenderer I simply replace the current HttpContext with a new one that hosts a Response that writes to a StringWriter.

This method works perfectly (a minor difference is that I had to create a separate Action for rendering my partial view, but no drama there).

查看更多
登录 后发表回答