Динамическая модель MVC Razor, "объект" не содержит определения для "PropertyName",

Использование MVC 3 с движком просмотра Razor. У меня есть этот вид:

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

В обоих представлениях, когда я отлаживаю их и наблюдаю за Model, он, кажется, содержит правильный объект. Когда я выполняю код, я получаю сообщение об ошибке в строке "var products =":

'object' не содержит определения для 'Products'

Может кто-нибудь объяснить мне, почему я получаю эту ошибку? Опять же, когда я смотрю объект Model в режиме отладки, он выглядит правильно (имеет 2 свойства: Products and Threshold)

Ответ 1

Вы передаете экземпляр анонимного класса в качестве модели представления? Я просто попробовал это (динамическая модель представления в CSHTML) и получил ту же ошибку, что и при использовании анонимного класса, но работал отлично, если я создал именованный класс. Я искал, но не видел этого документально.

// error
return View(new { Foo = 1, Bar = "test" });

// worked
return View(new TestClass { Foo = 1, Bar = "test" });

ИЗМЕНИТЬ № 1:

Согласно Дэвид Эббо, вы не можете пройти анонимный тип в динамически типизированное представление, потому что анонимные типы скомпилированы как internal. Поскольку представление CSHTML скомпилировано в отдельную сборку, оно не может получить доступ к свойствам анонимного типа.

ИЗМЕНИТЬ № 2:

Дэвид Эббо отредактировал свой пост с этим разъяснением:

Примечание (12/22/2011): теперь, когда MVC 3 имеет прямую поддержку динамического, ниже техника не нужна. Это сообщение на самом деле привело к интеграции функции в MVC!

Ответ 2

В .NET 4.0 Анонимные типы могут быть легко преобразованы в ExpandoObjects, и, следовательно, все проблемы исправлены с накладными расходами самого преобразования. Проверьте здесь

Ответ 3

Это не имеет ничего общего с анонимными типами, имеющими внутренние свойства

возможно передать анонимные типы из вида в частичный вид

Сегодня я столкнулся с той же проблемой, и ничто (непосредственно) не касалось проблемы передачи анонимных типов и их свойств internal.

Таким образом, по отношению к вопросу OPs ответ by @Lucas не имеет значения - даже если обходной путь будет работать.

В вопросе OPs анонимный тип передается из представления в сборке X в частичное в сборке X, поэтому проблема, которую Дэвид Эббо изложил о свойствах, являющихся внутренними для анонимных типов, без последствий; типы, скомпилированные для представления, частичный и анонимный типы содержатся в одной и той же сборке.

Итак, что вызывает внезапный отказ передать анонимный тип из представления в частичный?

По крайней мере, в ситуации my я обнаружил, что это связано с наличием другого представления в SAME FOLDER, который указывает тип модели, который не может быть разрешен. Представления компилируются во время выполнения, поэтому было бы разумно, поскольку отказ во время выполнения компиляции представлений также означал бы сбой компиляции динамических типов, а частичное просто получило бы object. Не сразу видно, что происходит, но в конкретном примере OP (и моем) это более чем вероятно причина проблемы.

Интересно отметить, что если тип модели верен, но другая часть представления не компилируется, то анонимные типы не затрагиваются одинаково. Это должно быть связано с тем, как Razor разбивает динамическую компиляцию составных частей представления.

Как только вы исправите нарушающий вид, перестройте все решение или очистите и перестройте проект, прежде чем проверять, исправлено ли это.

Чтобы убедиться, что вы снова не пойманы, вы можете включить компиляцию компиляции ваших просмотров Razor, добавив это в ваш файл csproj:

<PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>

Ответ 4

Добавьте следующий класс в ваше решение (используйте пространство имен 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());

Ответ 5

Вместо того, чтобы использовать тип модели 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>

Ответ 6

Я не уверен, что вы получаете эту ошибку, потому что не выполняете обход. Я получил ту же ошибку в частичном представлении. решение было просто очистить сборку и перестроить ее. если синтаксис верен, код должен работать, но механизм бритвы может не обновлять корректный код.

Ответ 7

Я работал над этой проблемой, используя словарь.

 @Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });

Ответ 8

Чтобы использовать тип dynamic, вам нужно ссылаться на Microsoft.CSharp assembly