renderpartial ด้วย null model ได้รับการพิมพ์ผิดประเภท


198

ฉันมีหน้า:

<%@ Page Inherits="System.Web.Mvc.View<DTOSearchResults>" %>

และบนมันต่อไปนี้:

<% Html.RenderPartial("TaskList", Model.Tasks); %>

นี่คือวัตถุ DTO:

public class DTOSearchResults
{
    public string SearchTerm { get; set; }
    public IEnumerable<Task> Tasks { get; set; }

และนี่คือบางส่วน:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Task>>" %>

เมื่อ Model.Tasks ไม่เป็นโมฆะทุกอย่างทำงานได้ดี อย่างไรก็ตามเมื่อเป็นโมฆะฉันได้รับ:

ไอเท็มโมเดลที่ส่งไปยังพจนานุกรมนั้นเป็นประเภท 'DTOSearchResults' แต่พจนานุกรมนี้ต้องการไอเท็มโมเดลที่เป็นชนิด 'System.Collections.Generic.IEnumerable`1 [Task]'

ฉันคิดว่ามันจะต้องไม่ทราบว่าจะใช้งานเกินพิกัดใดดังนั้นฉันจึงทำสิ่งนี้ (ดูด้านล่าง) ให้ชัดเจน แต่ฉันก็ยังได้รับปัญหาเดียวกัน!

<% Html.RenderPartial("TaskList", (object)Model.Tasks, null); %>

ฉันรู้ว่าฉันสามารถแก้ไขได้โดยตรวจสอบค่าว่างหรือไม่ผ่านค่าว่าง แต่นั่นไม่ใช่ประเด็น ทำไมสิ่งนี้จึงเกิดขึ้น

คำตอบ:


349

แอนดรูว์ฉันคิดว่าปัญหาที่คุณได้รับเป็นผลมาจากวิธี RenderPartial โดยใช้โมเดลการเรียก (ดู) ไปยังมุมมองบางส่วนเมื่อโมเดลที่คุณส่งเป็นโมฆะ .. คุณสามารถแก้ไขพฤติกรรมแปลก ๆ ได้โดยทำดังนี้

<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %>

มันช่วยได้ไหม


16
ยังช่วยประหยัดเวลาของผู้คน ฉันดึงผมออกมา
James Gregory

3
ฉันเข้าใจว่าทำไมพวกเขาถึงสนับสนุนโมเดลโมฆะและส่งต่อโมเดล แต่ไม่สามารถจัดการได้โดยการโหลดมากเกินไป @ Html.Render ("donkeys") แตกต่างจาก @ Html.Render ("donkeys", canbenull)
Phil Strong

19
ฉันพบว่ามันใช้ง่ายมากดังนั้นฉันจึงเพิ่ม "ปัญหา" ลงคะแนนถ้าคุณเห็นด้วย: aspnet.codeplex.com/workitem/8872
pbz

3
ฉันพบว่าด้วยวิธีนี้ ValidationSummary ของฉันในมุมมองบางส่วนของฉันไม่ทำงานเพราะ ViewData ของโมเดลหลักหายไปในมุมมองบางส่วน ฉันใช้คำตอบที่ระบุไว้ที่นี่ stackoverflow.com/a/12037580/649497เพื่อแก้ปัญหานี้
BruceHill

5
คุณควรผ่านไปตาม ViewData ที่มีอยู่: ใหม่ ViewDataDictionary (ViewData)
ScottE

48

คำตอบของ @ myandmycode นั้นดี แต่จะสั้นกว่าเล็กน้อย

<% Html.RenderPartial("TaskList", new ViewDataDictionary(Model.Tasks)); %>

ใช้งานได้เพราะViewDataDictionaryเป็นสิ่งที่เก็บแบบจำลองไว้และสามารถยอมรับแบบจำลองเป็นพารามิเตอร์ตัวสร้างได้ สิ่งนี้จะส่งผ่านพจนานุกรมข้อมูลการดู "ทั้งหมด" ซึ่งแน่นอนว่ามีเพียงโมเดลที่อาจเป็นโมฆะ


2
@jcmcbeth: เอ่อไม่ไม่ ... ฉันใช้รหัสตรงนี้กับ nulls เรียบร้อยแล้ว
กำหนดค่า

1
@jcmcbeth: คุณกำลังใช้งานnew ViewDataDictionary(null)หรือไม่ เพราะนั่นจะเลือกโอเวอร์โหลดที่แตกต่างกันหนึ่งอันที่มีViewDataDictionaryพารามิเตอร์ซึ่งอาจไม่ยอมรับโมฆะ
กำหนดค่า

1
ดูเหมือนว่าการใช้คุณสมบัติ ViewBag ทำให้ตัวสร้างที่ไม่ถูกต้องถูกเรียก วิธีใช้ประเภทไดนามิกและสมมติว่าเป็น ViewDataDictionary เหนือวัตถุไม่สมเหตุสมผลสำหรับฉัน แต่ดูเหมือนว่าเป็นสิ่งที่กำลังทำอยู่ คุณจะต้องโยนมันไปที่วัตถุเพื่อเลือกตัวสร้างที่ถูกต้อง
Joel McBeth

1
@jcmcbeth: การเรียกมันผ่านประเภทไดนามิกใช้เหมือนกับว่าคุณได้รับค่าจริง หากค่าnullนั้นเป็นเช่นเดียวกับการโทรnew ViewDataDictionary(null)ซึ่งทำให้โอเวอร์โหลดที่เฉพาะเจาะจงมากที่สุดถูกเรียก
กำหนดค่า

1
ถ้าคุณใช้มันในแบบนี้ข้อผิดพลาดของดิชเชอรี่จะหายไป .. Html.RenderPartial("TaskList", new ViewDataDictionary(model: Model.Tasks))คุณกำลังใช้คอนสตรัคเตอร์ที่ผิดถ้ามันว่าง
Filip Cornelissen

26

ปรากฏว่าเมื่อคุณสมบัติของโมเดลที่คุณกำลังส่งเป็น MVC ว่างโดยเจตนาเปลี่ยนกลับเป็นโมเดล "หลัก" เห็นได้ชัดว่าเครื่องยนต์ MVC ตีความค่ารูปแบบโมฆะเป็นเจตนาที่จะใช้ก่อนหน้านี้

รายละเอียดเพิ่มเติมเล็กน้อยที่นี่: ASP.NET MVC, มุมมองที่พิมพ์มาก, พารามิเตอร์มุมมองบางส่วนผิดพลาด


1
+1 สำหรับการพยายามอธิบายปัญหาจริง ๆ และไม่ใช่แค่ทำสิ่งนี้เป็นพฤติกรรมแปลก ๆ
YavgenyP

ใช่นี่คือสิ่งที่เกิดขึ้นกับฉันและข้างต้นไม่ได้แก้ไขมันก็แค่ให้ข้อมูลเพิ่มเติมเล็กน้อยเกี่ยวกับข้อผิดพลาดที่เกิดขึ้นจริงของฉัน
ผ้าใบ

20

หากคุณไม่ต้องการที่จะหลวม ViewData ก่อนหน้าของคุณในมุมมองบางส่วนคุณสามารถลอง:

<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary(ViewData){Model = null});%>

1
ดูเหมือนจะไม่ตอบคำถาม
จอห์นแซนเดอร์

6
+1 จริง ๆ แล้วมันใช้งานได้ โดยทั่วไปแล้วเป็นความคิดเดียวกันที่นำเสนอในที่นี้stackoverflow.com/a/713921/649497แต่เอาชนะปัญหากับคำตอบนั้นและนั่นคือ ViewData จะหายไปถ้าคุณสร้างอินสแตนซ์ของ ViewDataDictionary ด้วยตัวสร้างเปล่า ฉันก่อนแก้ไขปัญหานี้ด้วยวิธีการแก้ปัญหาที่ยอมรับแล้วพบว่า ValidationSummary ของฉันไม่ทำงานในมุมมองบางส่วน วิธีนี้แก้ไขได้สำหรับฉัน คำตอบนี้ต้องการการยอมรับมากขึ้นสำหรับการแก้ปัญหาและรักษา ViewData ในมุมมองบางส่วนของคุณ
BruceHill

1
@Franc P สามารถใช้งานได้จริงโดยไม่สูญเสียค่า ViewBag และส่งผ่านโมเดลที่ไม่มีค่า ขอบคุณ
Zaker

นี่คือคำตอบที่ถูกต้องหากคุณต้องการใช้ ViewBag ใน Partials ของคุณ!
Daniel Lorenz

12

ทางออกคือการสร้าง HtmlHelper เช่นนี้

public static MvcHtmlString Partial<T>(this HtmlHelper htmlHelper, string partialViewName, T model)
{
    ViewDataDictionary viewData = new ViewDataDictionary(htmlHelper.ViewData)
    {
        Model = model
    };
    return PartialExtensions.Partial(htmlHelper, partialViewName, model, viewData);
}

การPartial<T>(...)จับคู่ก่อนที่จะPartial(...)สะดวกและไม่มีข้อผิดพลาดความกำกวมเมื่อรวบรวม

โดยส่วนตัวแล้วฉันคิดว่ามันยากที่จะเข้าใจพฤติกรรม - ดูเหมือนยากที่จะจินตนาการว่านี่เป็นตัวเลือกการออกแบบ?


1
นี่คือสิ่งที่ฉันทำในท้ายที่สุด มีตัวเลือก / พฤติกรรมการออกแบบใน asp.net mvc ไม่มากนัก ตั้งแต่ทิ้งไว้ มีประโยชน์กับคนอื่น ๆ ดังนั้นโปรด +1
Andrew Bullock

ดีอย่างหนึ่ง แต่ไม่ชัดเจนสำหรับผู้ใช้ สมมติว่าฉันคุ้นเคยกับสิ่งที่เพื่อนร่วมงานของฉันใช้ในโครงการของเขาฉันเริ่มใหม่ จากนั้นลืมที่จะเพิ่มโอเวอร์โหลดและ voilla นี้โดยสิ้นเชิงข้อยกเว้นเริ่มเกิดขึ้นในการผลิตเพราะเราทดสอบไม่ดีพอ ชื่ออื่นคือ beter imho
Jaap

11

แม้ว่านี้ได้รับการตอบผมวิ่งข้ามนี้และตัดสินใจว่าผมต้องการที่จะแก้ปัญหานี้สำหรับโครงการของฉันแทนการทำงานรอบ ๆ new ViewDataDictionary()มันด้วย

ฉันสร้างชุดวิธีการขยาย: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
ฉันเพิ่มวิธีการบางอย่างที่ไม่เรียกบางส่วนถ้าแบบจำลองเป็นโมฆะ สิ่งนี้จะประหยัดได้ถ้ามีคำสั่งมากมาย

ฉันสร้างมันขึ้นมาเพื่อใช้กับมีดโกน แต่สองสามคนควรทำงานกับมุมมองสไตล์ aspx (มุมมองที่ใช้ HelperResult อาจเข้ากันไม่ได้)

วิธีการขยายมีลักษณะดังนี้:

@* calls the partial with Model = null *@
@Html.PartialOrNull("PartialName", null)
@* does not call the partial if the model is null *@
@Html.PartialOrDiscard("PartialName", null)

นอกจากนี้ยังมีวิธีการสำหรับIEnumerable<object>แบบจำลองและแบบที่ทิ้งก็สามารถเรียกใช้ด้วยแลมบ์ดามีดโกนที่ให้คุณห่อผลบางส่วนด้วย html

รู้สึกอิสระที่จะใช้พวกเขาหากคุณต้องการ


1
ยังคงมีประโยชน์ ณ MVC5: 6/25/2014 ขอบคุณ
Jason

1

วิธีแก้ปัญหาของฉันคือ:


<% Html.RenderPartial("TaskList", Model.Tasks ?? new List()); %>


นี่เป็นวิธีที่สกปรก ในมุมมองบางส่วนของคุณคุณควรจะสามารถตรวจสอบรูปแบบโมฆะแทนการตรวจสอบว่ารายการมีค่าใด ๆ และเป็นโมฆะ
madd
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.