ASP.NET MVC Razor: วิธีการแสดง HTML ของ Razor Partial View ภายในการทำงานของคอนโทรลเลอร์


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

ใช่นี่คือวิธีที่คุณแสดงมุมมองบางส่วนภายในมุมมอง แต่จะแสดงผลภายในแอ็คชันคอนโทรลเลอร์ได้อย่างไร?
Peter Stegnar

เยี่ยมมากตอนนี้! ทำงานร่วมกับสัญกรณ์ Razon และ ASP
Peter Stegnar

2
คำถามย่อยหนึ่งคำถาม: จะแสดงมุมมองที่อยู่ในขอบเขตคอนโทรลเลอร์อื่นจากนั้นเป็นปัจจุบันได้อย่างไร ให้บอกว่าอยู่ในขอบเขต "EmailController" (โฟลเดอร์ดูอีเมล)?
Peter Stegnar

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

การทำงานสำหรับมีดโกนและแบบฟอร์มบนเว็บ viewengines


ตรวจสอบลิงก์ @ChurkNorris เป็นผู้เขียนASP.net MVC Awesomeซึ่งเป็นผลิตภัณฑ์เชิงพาณิชย์จากเวอร์ชัน 2.0 (ปัจจุบันเปิดตัวล่าสุด 12 มีนาคม 2555) เวอร์ชัน 1.9 (รุ่นล่าสุดเมื่อวันที่ 9 มิถุนายน 2554) ยังคงเป็นโอเพ่นซอร์ส แต่อาจจะไม่ได้รับการพัฒนาอีกต่อไป ส้อม 1.9 มีไหม
Joel Purra

@Omu: RenderView ถือเป็นโมฆะ ดูmsdn.microsoft.com/en-us/library/…
roland

@ Roland นี่คือส่วนขยายคอนโทรลเลอร์ที่กำหนดเอง
Omu

1

ฉันเห็นว่ามีคนสงสัยว่าจะทำอย่างไรให้คอนโทรลเลอร์อื่น

ในกรณีของฉันฉันมีเทมเพลตอีเมลทั้งหมดในโฟลเดอร์ Views / Email แต่คุณสามารถแก้ไขสิ่งนี้เพื่อส่งผ่านในตัวควบคุมที่คุณมีมุมมองที่เกี่ยวข้อง

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เมธอดไม่ได้ใช้เส้นทางตรงเป็นพารามิเตอร์จึงต้องการไฟล์ControllerContext .

เมื่อเสร็จสิ้นการแสดงผลสตริงจะส่งคืน AccountController กลับสู่สถานะเริ่มต้นเพื่อใช้โดยอ็อบเจ็กต์การตอบสนอง


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 (string partialViewName, object model, ViewDataDictionary viewData) ได้หรือไม่ มีประโยชน์อย่างไรบ้างเนื่องจากต้องใช้ HtmlHelper?
bkqc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.