Есть ли способ заставить JavaScriptSerializer игнорировать свойства определенного универсального типа? - PullRequest
0 голосов
/ 28 июля 2011

Я использую Entity Framework для своих моделей, и мне нужно сериализовать их в JSON.Проблема в том, что EF включает в себя все эти действительно хорошие навигационные коллекции (например, моя модель User имеет свойство Orders), и когда я начинаю сериализацию этих объектов, сериализатор пытается получить значение для этих коллекций, и EF кричит на меня за попыткуиспользовать удаленный контекст

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

Я знаю, что могу украсить свои свойства с помощью[ScriptIgnore], чтобы заставить сериализатор оставить их в покое, но это проблема с EF, поскольку он генерирует код для этих свойств.

Есть ли способ заставить сериализатор не сериализовать свойства, которые имеют универсальный тип EntityCollection<>?

В качестве альтернативы есть способ сделать это с другой надежной библиотекой json, такой как JSON.Net?

Ответы [ 4 ]

8 голосов
/ 25 января 2013

Вы можете объявить пользовательский обработчик контракта, который указывает, какие свойства следует игнорировать. Вот универсальный "игнорируемый", основанный на ответе, который я нашел здесь :

/// <summary>
/// Special JsonConvert resolver that allows you to ignore properties.  See https://stackoverflow.com/a/13588192/1037948
/// </summary>
public class IgnorableSerializerContractResolver : DefaultContractResolver {
    protected readonly Dictionary<Type, HashSet<string>> Ignores;

    public IgnorableSerializerContractResolver() {
        this.Ignores = new Dictionary<Type, HashSet<string>>();
    }

    /// <summary>
    /// Explicitly ignore the given property(s) for the given type
    /// </summary>
    /// <param name="type"></param>
    /// <param name="propertyName">one or more properties to ignore.  Leave empty to ignore the type entirely.</param>
    public void Ignore(Type type, params string[] propertyName) {
        // start bucket if DNE
        if (!this.Ignores.ContainsKey(type)) this.Ignores[type] = new HashSet<string>();

        foreach (var prop in propertyName) {
            this.Ignores[type].Add(prop);
        }
    }

    /// <summary>
    /// Is the given property for the given type ignored?
    /// </summary>
    /// <param name="type"></param>
    /// <param name="propertyName"></param>
    /// <returns></returns>
    public bool IsIgnored(Type type, string propertyName) {
        if (!this.Ignores.ContainsKey(type)) return false;

        // if no properties provided, ignore the type entirely
        if (this.Ignores[type].Count == 0) return true;

        return this.Ignores[type].Contains(propertyName);
    }

    /// <summary>
    /// The decision logic goes here
    /// </summary>
    /// <param name="member"></param>
    /// <param name="memberSerialization"></param>
    /// <returns></returns>
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (this.IsIgnored(property.DeclaringType, property.PropertyName)) {
            property.ShouldSerialize = instance => { return false; };
        }

        return property;
    }
}

И использование:

var jsonResolver = new IgnorableSerializerContractResolver();
// ignore single property
jsonResolver.Ignore(typeof(Company), "WebSites");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };
3 голосов
/ 28 июля 2011

Если идея состоит в том, чтобы просто вернуть эти объекты на клиентскую сторону, почему бы вам просто не вернуть то, что вам нужно, используя анонимные классы?

Предполагая, что у вас есть этот ужасный тяжелый список объектов EntityFrameworkClass, вы можете сделать это:

var result = (from c in List<EntityFrameworkClass> 
             select new { 
                        PropertyINeedOne=c.EntityFrameworkClassProperty1,
                        PropertyINeedTwo=c.EntityFrameworkClassProperty2
              }).ToList();
0 голосов
/ 22 мая 2014

Это мой маленький вклад. Некоторые изменения в ответе @drzaus. Описание : Изменены некоторые изменения формы и Fluent включен. И небольшое исправление для использования PropertyType вместо DeclaringType.

public class IgnorableSerializerContractResolver : DefaultContractResolver
{
    protected readonly Dictionary<Type, HashSet<string>> Ignores;

    public IgnorableSerializerContractResolver()
    {
        Ignores = new Dictionary<Type, HashSet<string>>();
    }

    /// <summary>
    /// Explicitly ignore the given property(s) for the given type
    /// </summary>
    /// <param name="type"></param>
    /// <param name="propertyName">one or more properties to ignore.  Leave empty to ignore the type entirely.</param>
    public IgnorableSerializerContractResolver Ignore(Type type, params string[] propertyName)
    {
        // start bucket if DNE
        if (!Ignores.ContainsKey(type))
            Ignores[type] = new HashSet<string>();

        foreach (var prop in propertyName)
        {
            Ignores[type].Add(prop);
        }

        return this;
    }

    /// <summary>
    /// Is the given property for the given type ignored?
    /// </summary>
    /// <param name="type"></param>
    /// <param name="propertyName"></param>
    /// <returns></returns>
    public bool IsIgnored(Type type, string propertyName)
    {
        if (!Ignores.ContainsKey(type)) return false;

        // if no properties provided, ignore the type entirely
        return Ignores[type].Count == 0 || Ignores[type].Contains(propertyName);
    }

    /// <summary>
    /// The decision logic goes here
    /// </summary>
    /// <param name="member"></param>
    /// <param name="memberSerialization"></param>
    /// <returns></returns>
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (IsIgnored(property.PropertyType, property.PropertyName))
        {
            property.ShouldSerialize = instance => false;
        }

        return property;
    }
}

использование:

// Ignore by type, regardless property name
var jsonResolver = new IgnorableSerializerContractResolver().Ignore(typeof(PropertyName))
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };
0 голосов
/ 28 июля 2011

Если вы используете JSON.NET, вы можете использовать такие атрибуты, как JsonIgnore, чтобы игнорировать определенные свойства. Я использую эту функцию при сериализации объектов, загруженных через NHibernate.

Я думаю, что есть возможность добавлять соглашения. Может быть, вы можете реализовать фильтр для ваших свойств EF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...