ExpandoObject не содержит общедоступных свойств только в VS2013.

Я пытаюсь десериализовать свой объект JSON и передать его в качестве модели для своего представления. Поскольку я не знаю, какими свойствами будет обладать модель, я прочитал, что должен использовать ExpandoObject.

Вот что я пробовал:

public ActionResult Index()
{
    var myObj = new object();

    List<Dictionary<string, object>> container = new List<Dictionary<string, object>>()
    {
        new Dictionary<string, object> { { "Text", "Hello world" } }
    };
    JavaScriptSerializer json_serializer = new JavaScriptSerializer();
    myObj = json_serializer.DeserializeObject(json_serializer.Serialize(container));
    return View(myObj.ToExpando());
}

И в том же пространстве имен я определил этот класс:

public static class Helpers
{
    public static ExpandoObject ToExpando(this object anonymousObject)
    {
        IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
        IDictionary<string, object> expando = new ExpandoObject();
        foreach (var item in anonymousDictionary)
            expando.Add(item);
        return (ExpandoObject)expando;
    }
}

И, на мой взгляд, у меня есть этот цикл:

@foreach (var item in Model)
{
    @item.Text
}

Когда я запускаю, я получаю эту ошибку:

«System.Collections.Generic.KeyValuePair» не содержит определения «Текст».

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

Почему эти общедоступные свойства не таковы, чтобы я мог получить к ним доступ?

Изменить: здесь вы можете увидеть объектную модель Expando, которая передается моему представлению:

введите здесь описание изображения

Примечание. Похоже, что свойство SyncRoot содержит мой объект.

Изменить: это десериализованный объект:

введите здесь описание изображения


person user1477388    schedule 31.07.2014    source источник
comment
Я сделал это с VS2013, и я получаю тот же результат. Но в данном случае проблема не в ExpandoObject, а в десериализации json. Если вы посмотрите на правопреемников в вашем примере, это массив объектов. Свойства массива объектов: Length, LongLength, Rank, SyncRoot и т. д. Естественно, это то, что вы получаете в ExpandoObject. Если вы используете метод ToExpando() для более обычного объекта, он работает нормально. Например: var pet = new { Тип = Собака, Имя = Барки, Возраст = 6 }; pet.ToExpando() дает вам 3 свойства: Type, Name и Age.   -  person Moby Disk    schedule 01.08.2014
comment
@MobyDisk спасибо за тестирование в VS2013. Однако, как показано в моем последнем обновлении, десериализованный объект — это просто список из трех объектов. Дополнительные свойства (Length, LongLength и т. д.) не добавляются, пока я не преобразую их в ExpandoObject. Как я могу просто отправить то, что мне нужно (содержимое obj в моем последнем обновлении)? По сути, я думаю, что мне нужен рекурсивный ExpandoObject. сейчас погуглю...   -  person user1477388    schedule 01.08.2014
comment
На снимке экрана показано, что вы расширили свойства myObj[0]. Но код не вызывает myObj[0].ToExpando, он вызывает myObj.ToExpando(). На этом снимке экрана показаны 3 объекта. Вы пытаетесь сделать расширение свойств одного объекта или свойств 3 объектов?   -  person Moby Disk    schedule 01.08.2014
comment
Я пытаюсь просто вернуть все свои объекты в свое представление без необходимости их строгого ввода. У меня есть решение, я добавлю его в качестве ответа, однако оно не решает проблему глубоко вложенных объектов json.   -  person user1477388    schedule 01.08.2014
comment
Ах, я понимаю. Рекурсивный Expando. Хммм... Я немного побуду в chat.stackoverflow.com/rooms/58493/expando. ...   -  person Moby Disk    schedule 01.08.2014


Ответы (2)


Обратите внимание, что @item определяется как System.Collections.Generic.KeyValuePair на основании вашей ошибки.

Это означает, что у вас есть два свойства: Key и Value.

Вот два возможных решения:

@foreach (var item in Model.Values)
{
    @item.Id
}

or

@foreach (var item in Model)
{
    @item.Value.Id
}
person Nathan A    schedule 31.07.2014
comment
Ошибка, которую я получаю сейчас, это 'System.Dynamic.ExpandoObject' does not contain a definition for 'Values' - person user1477388; 31.07.2014
comment
Вы пробовали второй вариант? - person Nathan A; 31.07.2014
comment
Да, но это не работает, потому что элементы, которые он перебирает, не соответствуют тому, что я отправил модели. Он проходит через Length, LongLength, Rank, элемент, который я пытался изменить на @foreach (var item in Model.item), но он просто говорит 'System.Dynamic.ExpandoObject' does not contain a definition for 'item' - person user1477388; 31.07.2014
comment
Я обновил свой вопрос дословно воспроизводимым примером. - person user1477388; 31.07.2014
comment
Я проверил это с помощью одного из моих тестовых приложений MVC, и это сработало. Я могу нормально перебирать ExpandoObject. Однако мне пришлось удалить объявление @model в верхней части моего файла .cshtml, иначе он жаловался, что модель не соответствует типу. - person Moby Disk; 31.07.2014
comment
В вашем обновлении та же проблема. Это должно быть @item.Value.something. Поставьте точку останова на строку @item.Text и играйте в окне просмотра. - person Moby Disk; 31.07.2014
comment
@MobyDisk Вы используете MVC 5? Я попробовал ваши предложения, и @item.Value.Text равно нулю. @item.Value это 1. Ключ @item - это Length. - person user1477388; 31.07.2014
comment
@MobyDisk Я обновил вопрос скриншотом того, что вижу. - person user1477388; 31.07.2014

Решение для меня состояло в том, чтобы сделать что-то вроде этого (используя ExpandoObjectConverter):

var myObj = new object();

List<Dictionary<string, object>> container = new List<Dictionary<string, object>>()
{
    new Dictionary<string, object> { { "Text", "Hello world" } }
};
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
var converter = new ExpandoObjectConverter();
var obj = JsonConvert.DeserializeObject<IEnumerable<ExpandoObject>>(json_serializer.Serialize(container), converter);

return View(obj);

Однако это не относится к глубоко вложенным объектам JSON. Вероятно, я могу создать какой-то рекурсивный метод.

Печально, что фреймворк не поддерживает такое очевидное требование; если я что-то пропустил.

person user1477388    schedule 01.08.2014