ASP.NET MVC Razor: Cara membuat HTML Razor Partial View di dalam tindakan pengontrol

97

Cara menghasilkan HTML dari tampilan parsial tertentu pada mesin tampilan ASP.NET diketahui .

Namun jika fungsi ini digunakan pada tampilan sebagian pisau cukur, fungsi tersebut tidak berfungsi, karena pengecualian mengatakan tampilan sebagian tidak berasal dari "UserControl".

Bagaimana cara memperbaiki rendering untuk mendukung tampilan sebagian pisau cukur?

Saya memerlukan ini karena saya menghasilkan email dari tampilan parsial ini ...

MEMPERBARUI:

Kode yang gagal (@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();
    }
Peter Stegnar
sumber
1
Dapatkah Anda menunjukkan kode yang Anda miliki sejauh ini yang menghasilkan pengecualian?
mlibby

Jawaban:

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

Memperbarui

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();
    }
}
jgauffin.dll
sumber
Ya, ini adalah cara Anda merender tampilan parsial di dalam tampilan. Tetapi bagaimana cara membuatnya di dalam aksi pengontrol?
Peter Stegnar
Hebat ini sekarang! Bekerja dengan Razon dan notasi ASP.
Peter Stegnar
2
Satu subpertanyaan: Bagaimana cara merender tampilan yang ada di lingkup Pengontrol lain kemudian saat ini? Katakanlah itu ada dalam lingkup "EmailController" (folder tampilan Email)?
Peter Stegnar
1
Ini adalah solusi yang bagus. Saya memiliki kebutuhan yang tepat dengan email dan memilih untuk menggunakan ini.
uadrive
2
@AmeyKhadatkar: tidak. jquery adalah sisi klien, tampilan dibuat di sisi server sebelum dikirim ke browser.
jgauffin
8

Meskipun jawaban yang memadai telah diberikan, saya ingin mengusulkan solusi yang tidak terlalu bertele-tele, yang dapat digunakan tanpa metode helper yang tersedia di kelas pengontrol MVC. Menggunakan pustaka pihak ketiga yang disebut "RazorEngine", Anda dapat menggunakan file .Net IO untuk mendapatkan konten file pisau cukur dan memanggil

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

Dapatkan perpustakaan pihak ketiga di sini .

Scott Terry
sumber
5

Anda juga bisa menggunakan RenderView Controller extensiondari sini ( sumber )

dan gunakan seperti ini:

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

ini berfungsi untuk mesin tampilan pisau cukur dan formulir web

Omu
sumber
Telah memeriksa tautannya. @ChurkNorris adalah penulis ASP.net MVC Awesome , yang merupakan produk komersial dari versi 2.0 (saat ini rilis terbaru 12 Maret 2012). Versi 1.9 (rilis terbaru 9 Juni 2011) masih open source, tetapi mungkin tidak akan dikembangkan lagi. Ada garpu 1.9 di luar sana?
Joel Purra
@Omu: RenderView tidak berlaku. Lihat msdn.microsoft.com/en-us/library/…
roland
@Roland ini adalah ekstensi pengontrol khusus
Omu
1

Saya melihat seseorang bertanya-tanya bagaimana melakukannya untuk pengontrol lain.

Dalam kasus saya, saya memiliki semua templat email saya di folder Tampilan / Email, tetapi Anda dapat memodifikasi ini untuk meneruskan pengontrol di mana Anda memiliki pandangan yang terkait dengannya.

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

Pada dasarnya apa yang dilakukan ini adalah mengambil pengontrol, seperti AccountController dan memodifikasinya agar dianggap sebagai EmailController sehingga kode akan terlihat di Views/Emailfolder. Ini perlu dilakukan karena FindViewmetode tidak mengambil jalur lurus ke atas sebagai parameter, ia menginginkan a ControllerContext.

Setelah selesai merender string, itu mengembalikan AccountController kembali ke keadaan awalnya untuk digunakan oleh objek Respon.

Pria Muffin
sumber
1

kode yang bagus; sedikit petunjuk: jika Anda terkadang harus melewati lebih banyak data dan tidak hanya viewmodel ..

 if (model is ViewDataDictionary)
 {
     controller.ViewData = model as ViewDataDictionary;
 } else {
     controller.ViewData.Model = model;
 }
David Riewe
sumber
2
Anda belum menyelesaikan jawaban Anda
poohdedoo
0

Meminjam jawaban @jgauffin sebagai ekstensi 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);
    }
}

Penggunaan dalam tampilan pisau cukur:

Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)
abbaf33f
sumber
1
Bisakah Anda menjelaskan perbedaannya dengan menggunakan @ Html.P Partial (string partialViewName, model objek, ViewDataDictionary viewData)? Apa keuntungannya karena membutuhkan HtmlHelper?
bkqc