具有null模型的renderpartial传递了错误的类型


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不为null,则一切正常。但是,当它为null时,我得到:

传递到字典中的模型项的类型为“ DTOSearchResults”,但是此字典需要类型为“ System.Collections.Generic.IEnumerable'1 [Task]”的模型项。

我认为它一定不知道要使用哪个重载,因此我明确地做到了这一点(见下文),但仍然遇到相同的问题!

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

我知道我可以通过检查null甚至不传递null来解决此问题,但这不是重点。为什么会这样呢?

Answers:


349

Andrew,我认为您遇到的问题是RenderPartial方法的结果,该方法使用您传递的模型为null时对部分视图进行调用(视图)的模型。

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

有帮助吗?


16
仍在节省人们的时间。我正在为此扯头发。
James Gregory

3
我明白为什么他们支持空模型并传递页面模型,但是他们不能通过重载来处理。@ Html.Render(“ donkeys”)与@ Html.Render(“ donkeys”,maybenull)不同
Phil Strong

19
我发现这很违反直觉,因此我添加了一个“问题”,如果您同意,请对其进行表决:aspnet.codeplex.com/workitem/8872
pbz 2011年

3
我发现使用此解决方案时,我的局部视图中的ValidationSummary无法正常工作,因为主要模型的ViewData在局部视图中丢失了。我用这里给出的答案 stackoverflow.com/a/12037580/649497解决了这个问题。
BruceHill 2013年

5
您应该传递现有的ViewData:new ViewDataDictionary(ViewData)
ScottE 2014年

48

@myandmycode的答案是好的,但是稍微短一点的答案是

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

之所以起作用,ViewDataDictionary是因为拥有模型的东西,并且可以接受模型作为构造函数参数。这基本上通过了“整个”视图数据字典,该字典当然仅包含可能为空的模型。


2
@jcmcbeth:嗯,不,不是。。。我已经成功地将此代码与null一起使用了。
配置器

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))如果使用null,则使用错误的构造函数。
Filip Cornelissen,2015年

26

看来,当您传入的模型的属性为null时,MVC会有意地还原为“父”模型。显然,MVC引擎将空模型值解释为打算使用前一个模型值。

此处略有更多详细信息:ASP.NET MVC,强类型视图,部分视图参数故障


1
+1实际上是试图解释这个问题,而不仅仅是将其视为一种怪异的行为
YavgenyP 2012年

是的,这发生在我身上,而上面的方法并没有解决,它只是给了我更多有关我的实际错误的信息。
Canvas 2015年

20

如果您不想在部分视图中失去先前的ViewData,可以尝试:

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

1
这似乎无法回答问题。
约翰·桑德斯

6
+1确实有效。它基本上是此处stackoverflow.com/a/713921/649497上提出的相同想法,但是克服了该答案的问题,即如果使用空构造函数实例化ViewDataDictionary,则ViewData将丢失。我首先使用可接受的解决方案解决了这个问题,然后发现我的ValidationSummary在部分视图中不起作用。这个解决方案为我解决了。该答案需要更多的认识才能解决问题并在局部视图中保留ViewData。
BruceHill 2013年

1
@Franc P实际上可以在不丢失ViewBag值的情况下工作,因此传递了一个null模型。谢谢。
Zaker 2015年

如果您需要在Partials中访问ViewBag,这是正确的答案!
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

好的,但是对于用户来说还不清楚。假设我已经习惯了我的大学在他的项目中使用的东西,我开始了一个新的工作。然后完全忘了添加此重载和本意,异常开始在生产中发生,因为我们对它的测试不够好。别的名字叫better imho。
Jaap 2012年

11

尽管已经回答了这个问题,但我遇到了这个问题,并决定我想为我的项目解决此问题,而不是与解决new ViewDataDictionary()

我创建了一组扩展方法:https : //github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
我还添加了一些方法,如果模型为null,这些方法不会调用Partial ,这样可以节省很多if语句。

我为Razor创建了它们,但是其中一些还应该与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>模型的方法,也可以使用Razor lambda调用丢弃方法,该方法允许您使用部分html包装部分结果。

随意使用它们。


1
从MVC5开始仍然有用:6/25/2014。谢谢。
杰森

1

我的解决方法是:


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


这是一个肮脏的解决方案。在局部视图上,您​​应该能够检查是否为空Model,而不是检查list是否具有任何值以及是否为null。
madd
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.