Динамическая модель MVC Razor, "объект" не содержит определения для "PropertyName"
Использование MVC 3 с движком Razor View. У меня есть этот вид:
@model dynamic
@{
var products = (List<ListItemBaseModel>)Model.Products;
var threshold = (int)(Model.Threshold ?? 1);
var id = Guid.NewGuid().ToString();
}
Он вызывается из другого представления с использованием этого кода:
@Html.Partial("PartialViewName", new { Products = Model, Threshold = 5 })
В обоих представлениях, когда я отлаживаю их и смотрю модель, кажется, что она содержит правильный объект. Когда я выполняю код, я получаю сообщение об ошибке в строке "var products =":
"объект" не содержит определения "продукты"
Может кто-нибудь объяснить мне, почему я получаю эту ошибку? Опять же, когда я наблюдаю объект Model в режиме отладки, он выглядит хорошо (имеет 2 свойства: Products и Threshold)
7 ответов
Вы передаете экземпляр анонимного класса в качестве модели представления? Я только что попробовал это (модель динамического представления в CSHTML) и получил ту же ошибку, что и вы, при использовании анонимного класса, но он работал нормально, если я создал именованный класс. Я искал, но нигде не видел этого.
// error
return View(new { Foo = 1, Bar = "test" });
// worked
return View(new TestClass { Foo = 1, Bar = "test" });
РЕДАКТИРОВАНИЕ № 1:
Согласно Дэвиду Эббо, вы не можете передать анонимный тип в динамически типизированное представление, потому что анонимные типы компилируются как internal
, Поскольку представление CSHTML скомпилировано в отдельную сборку, оно не может получить доступ к свойствам анонимного типа.
РЕДАКТИРОВАТЬ № 2:
Дэвид Эббо отредактировал свой пост с этим разъяснением:
Примечание (22.12.2011): теперь, когда MVC 3 имеет прямую поддержку динамической обработки, описанная ниже техника больше не нужна. Этот пост фактически привел к интеграции этой функции в MVC!
В.NET 4.0 анонимные типы могут быть легко преобразованы в ExpandoObjects, и, таким образом, все проблемы устраняются с помощью издержек самого преобразования. Проверьте здесь
Это не имеет ничего общего с анонимными типами, имеющими внутренние свойства
Вполне возможно передать анонимные типы из представления в частичное представление
Я столкнулся с той же проблемой сегодня, и это не было (напрямую) связано с проблемой передачи анонимных типов и их присущих internal
свойства.
Таким образом, по отношению к вопросу OP ответ @Lucas не имеет значения - даже если обходной путь будет работать.
В вопросе OP анонимный тип передается из представления в сборке X в частичное в сборке X, поэтому проблема, которую Дэвид Эббо выделил для внутренних свойств анонимных типов, не имеет значения; типы, скомпилированные для представления, частичный и анонимный типы, содержатся в одной сборке.
Так что же вызывает внезапную неудачу в передаче анонимного типа из представления в частичное?
По крайней мере, в моей ситуации я обнаружил, что это произошло из-за наличия другого представления в ЖЕ ПАПЕ, который указывает тип модели, который не может быть разрешен. Представления компилируются во время выполнения, и поэтому будет иметь смысл, поскольку сбой во время выполнения для компиляции представлений также будет означать сбой при компиляции динамических типов, а частичное просто получит object
, Не сразу очевидно, что происходит, но в конкретном примере ОП (и моем) это более чем вероятно причина проблемы.
Интересно отметить, что если тип модели правильный, но другая часть представления не компилируется, то на анонимные типы это не влияет. Это должно быть связано с тем, как Razor разбивает динамическую компиляцию составных частей представления.
После того, как вы исправите неправильное представление, либо пересоберите все решение, либо очистите и пересоберите проект, прежде чем проверять, исправлено ли оно.
Чтобы убедиться, что вы не пойманы этим снова, вы можете включить компиляцию во время компиляции ваших представлений Razor, добавив это в свой csproj
файл:
<PropertyGroup>
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
Добавьте следующий класс в любое место вашего решения (используйте пространство имен System, чтобы его можно было использовать без добавления каких-либо ссылок) -
namespace System
{
public static class ExpandoHelper
{
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
}
}
Когда вы отправляете модель в представление, преобразуйте ее в Expando:
return View(new {x=4, y=6}.ToExpando());
Вместо использования dynamic
Тип модели в частичном представлении.
Вы можете вызвать атрибуты анонимного объекта, используя @ViewData.Eval("foo")
вместо @Model.foo
,
Тогда вы можете удалить @Model dynamic
с точки зрения.
Я столкнулся с этой проблемой недавно, когда передавал некоторые атрибуты между представлениями для интеграции с социальными комментариями Facebook. Пример кода:
Html.RenderPartial(@"Layouts/Partials/_Comments", new {currentUrl = Model.CurrentPage.GetAbsoluteUrl(), commentCount = 5 });
Тогда, на мой взгляд, у меня просто был этот div:
<div class="fb-comments" data-href="@ViewData.Eval("currentUrl")" data-numposts="@ViewData.Eval("commentCount")" data-width="100%"></div>
Я не уверен, что вы получаете эту ошибку, потому что вы не реализуете обходной путь. я получил ту же ошибку в частичном представлении. решение было просто очистить сборку и перестроить ее. если синтаксис правильный, код должен работать, но движок бритвы может не обновлять изменения кода должным образом.
Я работал над этой проблемой, используя словарь.
@Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });
Использовать dynamic
типа нужно ссылаться Microsoft.CSharp
сборка