[c#] Eigenschaft von Serialisierung über benutzerdefiniertes Attribut ausschließen (json.net)


2 Answers

Hier ist ein generischer wiederverwendbarer Resolver "ignore property" basierend auf der akzeptierten Antwort :

/// <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)
        // need to check basetype as well for EF -- @per comment by user576838
        || this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName)) {
            property.ShouldSerialize = instance => { return false; };
        }

        return property;
    }
}

Und Verwendung:

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 };
Question

Ich muss in der Lage sein zu steuern, wie / ob bestimmte Eigenschaften einer Klasse serialisiert werden. Der einfachste Fall ist [ScriptIgnore] . Ich möchte jedoch nur, dass diese Attribute für diese eine bestimmte Serialisierungssituation, an der ich arbeite, berücksichtigt werden. Wenn andere Module in der Anwendung diese Objekte ebenfalls serialisieren möchten, sollte keines dieser Attribute in die Quere kommen.

Mein Gedanke ist also, ein benutzerdefiniertes Attribut MyAttribute für die Eigenschaften zu verwenden und die spezifische Instanz von JsonSerializer mit einem Hook zu initialisieren, der nach diesem Attribut sucht.

Auf den ersten Blick sehe ich nicht, dass einer der verfügbaren Hook-Punkte in JSON.NET die PropertyInfo für die aktuelle Eigenschaft bereitstellt, um eine solche Inspektion durchzuführen - nur den Wert der Eigenschaft. Fehle ich etwas? Oder ein besserer Weg, um das zu erreichen?




Ich hatte gute Ergebnisse mit der Kombination von Drzaus und Steve Rukuts Antworten. Allerdings habe ich ein Problem, wenn ich JsonPropertyAttribute mit einem anderen Namen oder Caps für die Eigenschaft festlegen. Beispielsweise:

[JsonProperty("username")]
public string Username { get; set; }

Berücksichtigung von BasiswertName löst das Problem:

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
    JsonProperty property = base.CreateProperty(member, memberSerialization);

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

    return property;
}



Hier ist eine Methode, die auf dem exzellenten Serializer-Vertrag von drzaus basiert, der Lambda-Ausdrücke verwendet. Fügen Sie es einfach derselben Klasse hinzu. Wer bevorzugt nicht, dass der Compiler die Überprüfung für sie durchführt?

public IgnorableSerializerContractResolver Ignore<TModel>(Expression<Func<TModel, object>> selector)
{
    MemberExpression body = selector.Body as MemberExpression;

    if (body == null)
    {
        UnaryExpression ubody = (UnaryExpression)selector.Body;
        body = ubody.Operand as MemberExpression;

        if (body == null)
        {
            throw new ArgumentException("Could not get property name", "selector");
        }
    }

    string propertyName = body.Member.Name;
    this.Ignore(typeof (TModel), propertyName);
    return this;
}

Sie können nun Eigenschaften einfach und fließend ignorieren:

contract.Ignore<Node>(node => node.NextNode)
    .Ignore<Node>(node => node.AvailableNodes);



Related