Рендеринг вида на лету

Я разрабатываю приложение ASP.NET MVC, которое отправит пользователю электронное письмо с подтверждением. Для самого электронного письма я хотел бы создать представление, а затем визуализировать это представление и отправить его с помощью почтовых объектов .NET.

Как я могу сделать это с помощью инфраструктуры MVC?


person Jonathan    schedule 04.03.2009    source источник
comment
Я думаю, вы имеете в виду MVC, а не MCV   -  person Richard Szalay    schedule 04.03.2009
comment
Не могу поверить, что я набрал 2 опечатки подряд, и в обеих одно и то же слово!   -  person Jonathan    schedule 04.03.2009


Ответы (3)


Вам в основном нужно использовать IView.Render. Вы можете получить представление, используя ViewEngineCollection.FindView (ViewEngines.Engines.FindView для значений по умолчанию). Выполните рендеринг вывода в TextWriter и убедитесь, что после этого вы вызываете ViewEngine.ReleaseView. Пример кода ниже (непроверенный):

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

Я оставлю вам viewData / tempData.

person Richard Szalay    schedule 04.03.2009
comment
Этот метод работал после некоторых изменений, за исключением того, что он приводил к следующей ошибке: Невозможно выполнить перенаправление после отправки заголовков HTTP. Это как-то связано с отправкой HTTP-заголовков в общий объект Response, а не в собственный поток (извините, мое понимание объектов .NET HTTP - это еще не все). - person Jonathan; 04.09.2009
comment
Почему это вообще перенаправление? - person Richard Szalay; 04.09.2009
comment
Что на самом деле делает ReleaseView? Это действительно важно? Что, если я не буду называть это? - person NightElfik; 14.01.2014

Согласно моему комментарию к ответу Ричарда, этот код действительно работал, но всегда приводил к ошибке «Невозможно перенаправить после отправки заголовков HTTP».

После множества копаний в Google и разочарований, я наконец нашел в этой статье код, который, кажется, помогает:

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

Метод этого парня - создать свой собственный HttpContext.

Вместо того, чтобы использовать MVCContrib BlockRenderer, я просто заменяю текущий HttpContext новым, содержащим ответ, который записывает в StringWriter.

Этот метод работает отлично (небольшая разница в том, что мне пришлось создать отдельный Action для рендеринга моего частичного представления, но никакой драмы здесь нет).

person Jonathan    schedule 04.09.2009

Это сработало для меня:

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);
                    }
                }
            }
        }
    }
}
person Paul C    schedule 12.11.2013