ASP.NET MVC Razor: Як візуалізувати HTML часткового виду бритви всередині дії контролера


97

Як генерувати HTML заданого часткового перегляду на двигуні перегляду ASP.NET відомо .

Але якщо ця функціональність використовується для часткового перегляду бритви, вона не працює, як виняток говорить, що частковий вигляд не походить від "UserControl".

Як виправити візуалізацію для підтримки часткового перегляду бритви?

Мені це потрібно, тому що я генерую електронні листи з цих часткових переглядів ...

ОНОВЛЕННЯ:

Код, який не вдається (@mcl):

public string RenderPartialToString(string controlName, object viewData)
    {
        ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
        viewPage.Url = this.GetUrlHelper();

        string fullControlName = "~/Views/Email/" + controlName + ".ascx";

        viewPage.ViewData = new ViewDataDictionary(viewData);
        viewPage.Controls.Add(viewPage.LoadControl(fullControlName));

        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            using (HtmlTextWriter tw = new HtmlTextWriter(sw))
            {
                viewPage.RenderControl(tw);
            }
        }
        return sb.ToString();
    }

1
Чи можете ви показати досі наявний код, який генерує виняток?
mlibby

Відповіді:


154
@Html.Partial("nameOfPartial", Model)

Оновлення

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

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

Так, саме так ви створюєте частковий вигляд усередині подання. Але як зробити це всередині дії контролера?
Петро Стегнар

Чудово це зараз! Працює з позначеннями Razon і ASP.
Петро Стегнар

2
Один підступіум: Як візуалізувати подання, яке знаходиться в іншій області контролера, ніж поточне? Скажімо, це в області "EmailController" (папка перегляду електронної пошти)?
Петро Стегнар

1
Це було чудове рішення. У мене була точна потреба в електронній пошті і вирішили використовувати це.
uadrive

2
@AmeyKhadatkar: ні. jquery - це клієнт, подання створюється на стороні сервера, перш ніж надсилатись у браузер.
jgauffin

8

Хоча відповіді вже надано, я хочу запропонувати менш детальне рішення, яке можна використовувати без допоміжних методів, доступних у класі контролера MVC. Використовуючи сторонні бібліотеки під назвою "RazorEngine", ви можете використовувати .Net файл IO, щоб отримати вміст файлу бритви та зателефонувати

string html = Razor.Parse(razorViewContentString, modelObject);

Отримати бібліотеку третьої сторони тут .


5

Крім того, можна використовувати RenderView Controller extensionз тут ( джерело )

і використовувати його так:

public ActionResult Do() {
var html = this.RenderView("index", theModel);
...
}

він працює для виглядів бритви та веб-форм


Перевірив посилання. @ChurkNorris є автором ASP.net MVC Awesome , комерційного продукту версії 2.0 (останній реліз 12 березня 2012 р.). Версія 1.9 (остання версія 9 червня 2011 р.) Все ще є відкритим кодом, але, ймовірно, більше не розроблятиметься. Будь-які виделки на 1.9?
Джоел Пурра

@Omu: RenderView недійсний. Дивіться msdn.microsoft.com/en-us/library/…
roland

@Roland це власне розширення контролера
Ому

1

Я бачив, що хтось цікавився, як це зробити для іншого контролера.

У моєму випадку у мене були всі мої шаблони електронної пошти у папці Перегляди / Електронна пошта, але ви можете змінити це, щоб перейти до контролера, для якого у вас пов’язані представлення.

public static string RenderViewToString(Controller controller, string viewName, object model)
    {
        var oldController = controller.RouteData.Values["controller"].ToString();

        if (controller.GetType() != typeof(EmailController))
            controller.RouteData.Values["controller"] = "Email";

        var oldModel = controller.ViewData.Model;
        controller.ViewData.Model = model;
        try
        {
            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName,
                                                                           null);

                var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                //Cleanup
                controller.ViewData.Model = oldModel;
                controller.RouteData.Values["controller"] = oldController;

                return sw.GetStringBuilder().ToString();
            }
        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

            throw ex;
        }
    }

По суті, для цього потрібно взяти контролер, такий як AccountController, і змінити його, щоб він міг вважати EmailController, щоб код виглядав у Views/Emailпапці. Це потрібно зробити, оскільки FindViewметод не приймає прямий шлях в якості параметра, він хоче a ControllerContext.

Після завершення надання рядка він повертає AccountController назад у початковий стан, який буде використовуватися об'єктом Response.


1

чудовий код; невеликий натяк: якщо вам іноді доводиться обходити більше даних, а не лише модуля перегляду ..

 if (model is ViewDataDictionary)
 {
     controller.ViewData = model as ViewDataDictionary;
 } else {
     controller.ViewData.Model = model;
 }

2
Ви ще не виконали свою відповідь
poohdedoo

0

Запозичення @jgauffin відповідь як розширення HtmlHelper:

public static class HtmlHelperExtensions
{
    public static MvcHtmlString RenderPartialViewToString(
        this HtmlHelper html, 
        ControllerContext controllerContext, 
        ViewDataDictionary viewData,
        TempDataDictionary tempData,
        string viewName, 
        object model)
    {
        viewData.Model = model;
        string result = String.Empty;

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

            result = sw.GetStringBuilder().ToString();
        }

        return MvcHtmlString.Create(result);
    }
}

Використання у вигляді бритви:

Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)

1
Чи можете ви пояснити різницю за допомогою @ Html.Partial (рядок partViewName, об'єктна модель, ViewDataDictionary viewData)? Які переваги, оскільки він вимагає HtmlHelper?
bkqc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.