kết xuất với mô hình null được truyền sai loại


198

Tôi có một trang:

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

Và trên đó, như sau:

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

Đây là đối tượng DTO:

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

và đây là một phần:

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

Khi Model.T Nhiệm vụ không có giá trị, mọi thứ đều hoạt động tốt. Tuy nhiên, khi null, tôi nhận được:

Mục mô hình được truyền vào từ điển thuộc loại 'DTOSearchResults' nhưng từ điển này yêu cầu một mục mô hình thuộc loại 'System.Collections.Generic.IEnumerable`1 [Nhiệm vụ]'.

Tôi hình dung nó phải không biết sử dụng quá tải nào, vì vậy tôi đã làm điều này (xem bên dưới) để rõ ràng, nhưng tôi vẫn gặp vấn đề tương tự!

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

Tôi biết tôi có thể giải quyết vấn đề này bằng cách kiểm tra null hoặc thậm chí không chuyển null, nhưng đó không phải là vấn đề. Tại sao chuyện này đang xảy ra?

Câu trả lời:


349

Andrew Tôi nghĩ rằng vấn đề bạn gặp phải là kết quả của phương thức RenderPartial khi sử dụng mô hình của chế độ gọi (chế độ xem) cho chế độ xem một phần khi mô hình bạn vượt qua là null .. bạn có thể khắc phục hành vi kỳ quặc này bằng cách thực hiện:

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

cái đó có giúp ích không?


16
Vẫn tiết kiệm thời gian cho mọi người. Tôi đã kéo tóc của tôi ra về điều này.
James Gregory

3
Tôi hiểu lý do tại sao họ hỗ trợ mô hình null và vượt qua các trang Mô hình nhưng họ không thể xử lý điều đó bằng cách quá tải. @ Html.Render ("lừa") khác với @ Html.Render ("lừa", canbenull)
Phil Strong

19
Tôi thấy điều này rất phản trực giác nên tôi đã thêm một "vấn đề", bỏ phiếu nếu bạn đồng ý: aspnet.codeplex.com/workitem/8872
pbz

3
Tôi thấy rằng với giải pháp này, ValidationSummary trong chế độ xem một phần của tôi không hoạt động vì ViewData của mô hình chính bị mất trong chế độ xem một phần. Tôi đã sử dụng câu trả lời được đưa ra ở đây stackoverflow.com/a/12037580/649497 để giải quyết điều này.
BruceHill

5
Bạn nên vượt qua ViewData hiện tại: ViewDataDixi mới (ViewData)
ScottE

48

Câu trả lời của @ myandmycode là tốt, nhưng câu trả lời ngắn hơn một chút sẽ là

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

Điều này hoạt động bởi vì đó ViewDataDictionarylà thứ chứa mô hình và nó có thể chấp nhận một mô hình như là một tham số của hàm tạo. Điều này về cơ bản vượt qua một từ điển dữ liệu xem "toàn bộ", tất nhiên chỉ chứa mô hình có thể null.


2
@jcmcbeth: Erm, không, không ... Tôi đã sử dụng mã chính xác này với null thành công.
cấu hình

1
@jcmcbeth: Bạn đang sử dụng new ViewDataDictionary(null)? Bởi vì điều đó sẽ chọn một quá tải khác nhau, một với một ViewDataDictionarytham số, có thể sẽ không chấp nhận null.
cấu hình

1
Dường như việc sử dụng thuộc tính ViewBag khiến hàm tạo sai được gọi. Làm thế nào nó có một kiểu động và giả sử đó là ViewDataDipedia trên một đối tượng không có ý nghĩa với tôi, nhưng dường như đó là những gì nó đang làm. Bạn sẽ phải truyền nó tới một đối tượng cho nó để chọn đúng hàm tạo.
Joel McBeth

1
@jcmcbeth: Gọi nó qua một loại động sử dụng giống như khi bạn đưa ra giá trị thực tế; nếu giá trị là null, điều đó giống như cách gọi new ViewDataDictionary(null)gây ra tình trạng quá tải cụ thể nhất được gọi.
cấu hình

1
nếu bạn sử dụng nó như thế này, lỗi từ điển sẽ biến mất .. Html.RenderPartial("TaskList", new ViewDataDictionary(model: Model.Tasks))Bạn đang sử dụng hàm tạo sai nếu nó không có giá trị.
Filip Cornelissen

26

Có vẻ như khi thuộc tính của Mô hình bạn truyền vào là null MVC cố ý hoàn nguyên về Mô hình "cha mẹ". Rõ ràng công cụ MVC diễn giải giá trị mô hình null là ý định sử dụng giá trị trước đó.

Chi tiết hơn một chút ở đây: ASP.NET MVC, các kiểu xem được gõ mạnh, các tham số xem một phần trục trặc


1
+1 vì thực sự cố gắng giải thích vấn đề và không chỉ coi đây là hành vi kỳ quặc
YavgenyP

Đúng, điều này đã xảy ra với tôi và ở trên đã không khắc phục được, nó chỉ cung cấp cho tôi thêm một chút thông tin về lỗi thực tế của tôi.
Canvas

20

Nếu bạn không muốn mất ViewData trước đó trong chế độ xem một phần, bạn có thể thử:

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

1
Điều này dường như không trả lời câu hỏi.
John Saunders

6
+1 Trên thực tế, nó hoạt động. Về cơ bản, đó là cùng một ý tưởng được trình bày ở đây stackoverflow.com/a/713921/649497 nhưng khắc phục được vấn đề với câu trả lời đó và đó là ViewData sẽ bị mất nếu bạn khởi tạo ViewDataDipedia bằng một hàm tạo trống. Trước tiên tôi đã giải quyết vấn đề này bằng giải pháp được chấp nhận và sau đó thấy rằng ValidationSummary của tôi không hoạt động trong chế độ xem một phần. Giải pháp này đã giải quyết điều đó cho tôi. Câu trả lời này cần được công nhận nhiều hơn để giải quyết vấn đề và duy trì ViewData trong chế độ xem một phần của bạn.
BruceHill

1
@Franc P này thực sự hoạt động mà không mất các giá trị ViewBag và do đó đã vượt qua một mô hình null. Cảm ơn.
Zaker

Đây là câu trả lời đúng nếu bạn cần quyền truy cập ViewBag trong Partials của bạn!
Daniel Lorenz

12

Một giải pháp sẽ là tạo một HtmlHelper như thế này:

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

Việc Partial<T>(...)khớp trước Partial(...)rất thuận tiện và không có lỗi mơ hồ khi biên dịch.

Cá nhân tôi thấy khó hiểu hành vi - có vẻ khó tưởng tượng đây là sự lựa chọn thiết kế?


1
đây là những gì tôi đã làm cuối cùng không có nhiều lựa chọn / hành vi thiết kế trong asp.net mvc có ý nghĩa gì. kể từ khi bỏ rơi nó hữu ích cho những người khác, vì vậy hãy có +1
Andrew Bullock

Tốt, tuy nhiên không rõ ràng cho người dùng. Giả sử tôi đã quen với những gì mà đồng nghiệp của tôi sử dụng trong dự án của anh ấy, tôi bắt đầu một cái mới. Sau đó, hoàn toàn quên thêm quá tải và voilla này, các ngoại lệ bắt đầu xảy ra trong sản xuất vì chúng tôi đã không kiểm tra nó đủ tốt. Một tên khác là beter imho.
Jaap

11

Mặc dù điều này đã được trả lời, tôi đã chạy qua vấn đề này và quyết định tôi muốn giải quyết vấn đề này cho dự án của mình thay vì làm việc với nó new ViewDataDictionary().

Tôi đã tạo một tập hợp các phương thức mở rộng: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
Tôi cũng đã thêm một số phương thức không gọi một phần nếu mô hình là null , điều này sẽ tiết kiệm rất nhiều nếu báo cáo.

Tôi đã tạo chúng cho Dao cạo, nhưng một vài trong số chúng cũng nên hoạt động với chế độ xem kiểu aspx (những cái sử dụng HelperResult có thể không tương thích).

Các phương thức mở rộng trông như thế này:

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

Ngoài ra còn có các phương pháp cho IEnumerable<object> các mô hình và các mô hình loại bỏ cũng có thể được gọi bằng một lambda Dao cạo cho phép bạn bọc kết quả một phần bằng một số html.

Hãy sử dụng chúng nếu bạn thích.


1
Vẫn hữu ích kể từ MVC5: 25/11/2014. Cảm ơn.
Jason

1

Cách giải quyết của tôi là:


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


Đây là một giải pháp bẩn. Trên chế độ xem một phần của bạn, bạn sẽ có thể kiểm tra Mô hình null, thay vì kiểm tra xem danh sách có bất kỳ giá trị nào không và nếu nó không.
buồn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.