ASP.NET MVC Razor: Denetleyici eylemi içinde Razor Kısmi Görünüm HTML'sini oluşturma


97

ASP.NET görünüm motorunda belirli bir kısmi görünümün HTML'sinin nasıl oluşturulacağı bilinmektedir .

Ancak bu işlevsellik tıraş bıçağı kısmi görünümünde kullanılırsa çalışmaz çünkü istisna, kısmi görünümün "UserControl" den türetilmediğini belirtir.

Jilet kısmi görünümünü desteklemek için işleme nasıl düzeltilir?

Buna ihtiyacım var çünkü bu kısmi görünümlerden e-postalar oluşturuyorum ...

GÜNCELLEME:

Başarısız olan kod (@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
İstisnayı oluşturan şu ana kadar sahip olduğunuz kodu gösterebilir misiniz?
mlibby

Yanıtlar:


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

Güncelleme

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

Evet, bir görünümün içinde kısmi görünümü bu şekilde oluşturursunuz. Ancak bunu bir denetleyici eylemi içinde nasıl işleyebilirim?
Peter Stegnar

Harika, şimdi bu kadar! Razon ve ASP gösterimi ile çalışır.
Peter Stegnar

2
Bir alt sorgulama: Başka bir Denetleyici kapsamındaki görünüm daha sonra mevcut görünüm nasıl işlenir? Diyelim ki "EmailController" kapsamında (E-posta görünümü klasörü)?
Peter Stegnar

1
Bu harika bir çözümdü. E-postayla tam olarak ihtiyacım vardı ve bunu kullanmayı seçtim.
uadrive

2
@AmeyKhadatkar: hayır. jquery istemci tarafıdır, görünüm tarayıcıya gönderilmeden önce sunucu tarafında oluşturulur.
jgauffin

8

Yeterli cevaplar zaten verilmiş olmasına rağmen, bir MVC denetleyici sınıfında bulunan yardımcı yöntemler olmadan kullanılabilecek daha az ayrıntılı bir çözüm önermek istiyorum. "RazorEngine" adlı üçüncü taraf bir kitaplığı kullanarak, jilet dosyasının içeriğini almak ve çağrı yapmak için .Net dosyası IO'yu kullanabilirsiniz.

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

Üçüncü taraf kitaplığını buradan edinin .


5

Ayrıca kullanabilirsiniz RenderView Controller extensiondan burada ( kaynak )

ve şu şekilde kullanın:

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

bunun için çalışır jilet ve web formları viewengines


Bağlantıyı kontrol ettim. @ChurkNorris, 2.0 sürümünden ticari bir ürün olan ASP.net MVC Awesome'in yazarıdır (şu anda en son sürüm 12 Mart 2012). Sürüm 1.9 (en son sürüm 9 Haziran 2011) hala açık kaynaktır, ancak muhtemelen artık geliştirilmeyecektir. Orada 1,9 çatal var mı?
Joel Purra

@Omu: RenderView geçersizdir. Bkz msdn.microsoft.com/en-us/library/...
roland

@Roland, bu özel bir denetleyici uzantısı
Omu

1

Birisinin başka bir kontrolör için nasıl yapılacağını merak ettiğini gördüm.

Benim durumumda, tüm e-posta şablonlarım Görünümler / E-posta klasöründeydi, ancak bunu, ilişkili görünümlerinizin olduğu denetleyiciye geçmek için değiştirebilirsiniz.

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

Esasen bunun yaptığı, AccountController gibi bir denetleyiciyi almak ve onu bir EmailController olarak değiştirerek kodun Views/Emailklasöre bakmasını sağlamaktır . Bunu yapmak gerekiyor çünkü FindViewyöntem parametre olarak düz bir yol izlemiyor, bir ControllerContext.

Dize oluşturulduktan sonra, AccountController'ı Response nesnesi tarafından kullanılmak üzere başlangıç ​​durumuna geri döndürür.


1

harika kod; küçük ipucu: bazen yalnızca görünüm modelini değil, daha fazla veriyi atlamanız gerekiyorsa ..

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

2
Cevabınızı tamamlamadınız
poohdedoo

0

HtmlHelper uzantısı olarak @jgauffin yanıtını ödünç almak:

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

Jilet görünümünde kullanım:

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

1
@ Html.Partial (string kısmiViewName, nesne modeli, ViewDataDictionary viewData) kullanarak farkı açıklayabilir misiniz? HtmlHelper gerektirdiğinden faydaları nelerdir?
bkqc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.