programing

역직렬화 중 JSON.Net 무시 속성

starjava 2023. 2. 26. 08:40
반응형

역직렬화 중 JSON.Net 무시 속성

클래스는 다음과 같이 설정되어 있습니다.

public class Foo
{
    public string string1 { get; set; }
    public string string2 { get; set; }
    public string string3 { get; set; }
}

Json을 사용하고 있습니다.Net: 다음 Json 응답을 역직렬화합니다.

[
    {
        "number1": 1,
        "number2": 12345678901234567890,
        "number3": 3
    },
    {
        "number1": 9,
        "number2": 12345678901234567890,
        "number3": 8
    }
]

역직렬화 코드:

string json = @"[
    {
        ""number1"": 1,
        ""number2"": 12345678901234567890,
        ""number3"": 3
    },
    {
        ""number1"": 9,
        ""number2"": 12345678901234567890,
        ""number3"": 8
    }
]"

List<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(json);

의 값number21을 넘다Int64그 값을 취득하는 것은 별로 신경 쓰지 않습니다.캐스트 할 수 있는 방법이 있을까요?number2속성을 문자열에 저장할지, 아니면 역직렬화 중에 완전히 무시할지.

를 추가해 보았습니다.[JsonConverter(typeof(string))]의 탓으로 돌리다string2다음 오류를 수신합니다.Error creating System.String설정도 시도했습니다.typeof(decimal).

저도 써봤어요.[JsonIgnore]하지만 소용없어요.

사용할 수 있습니다.MissingMemberHandling의 특성JsonSerializerSettings물건.

사용 예:

var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;

JsonConvert.DeserializeObject<YourClass>(jsonResponse, jsonSerializerSettings);

자세한 것은 이쪽.

이 문제는 해결 방법이 부족하지만 수동으로 json을 로드하는 방법을 만들 수 있습니다.자동 디시리얼라이저 없이 로드하기에는 데이터가 너무 많은 경우 원하지 않는 노드를 삭제하십시오.이게 좀 느리긴 한데.

public static List<Foo> FromJson(string input) {
    var json = JToken.Parse(input);
    json["key"].Remove();
    var foo = JsonConvert.DeserializeObject<List<Foo>>(json.ToString());

}

이 문제는 흥미로운 문제인데, 이에 대한 더 나은 해결책을 가진 사람이 있는지 궁금합니다.

다음은 Newtonsoft Json이 선호하는 속성 무시 방법입니다. http://james.newtonking.com/json/help/index.html?topic=html/ReducingSerializedJSONSize.htm에 따라 클래스를 수정할 필요가 없습니다.

이것은 EF 또는 Linq2Sql의 느린 참조 속성을 무시하는 데 사용됩니다.

public class DynamicContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, 
        MemberSerialization memberSerialization)
    {
        Func<Type,bool> includeProperty = t => t.IsValueType || t.Namespace.StartsWith("System") && t.Namespace.StartsWith("System.Data")==false; 
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        var allProperties = properties.Select (p => new{p.PropertyName,Including=includeProperty(p.PropertyType), p.PropertyType});//.Dump("props");
        var warnProperties=allProperties.Where (a =>a.Including && a.PropertyType.IsValueType==false && a.PropertyType.Name.IsIgnoreCaseMatch("String")==false) ;

        //linq pad debugging helper
        //var propertyTypesSerializing= allProperties.Where (p => p.Including).Select (p => p.PropertyType).Distinct().OrderBy (p => p.Name).Dump();

        if(warnProperties.Any())
        {
            //LinqPad helper
            //Util.Highlight(warnProperties.ToArray()).Dump("warning flag raised, aborting");
            throw new ArgumentOutOfRangeException();
        }

        properties = properties.Where(p =>includeProperty(p.PropertyType)).ToList();
        return properties;
    }
}

모든..Dump()콜은 linqpad 디버깅도우미일 뿐 메서드콜은 필요 없습니다.

사용 예:

var inactives = from am in Aspnet_Memberships
        join mm in Member_members on am.UserId equals mm.Member_guid
        where mm.Is_active==false && mm.Org_id==1
        select new{am,mm};
        //inactives.Take(4).ToArray().Dump();
        var serialized = JsonConvert.SerializeObject(
            inactives.Skip(1).Select(i => i.mm).First(), 
            new  JsonSerializerSettings()
            {
                ContractResolver = new DynamicContractResolver(), 
                PreserveReferencesHandling = PreserveReferencesHandling.None,
                ReferenceLoopHandling= ReferenceLoopHandling.Ignore
            }); 
            //.Dump();

@Maslow의 솔루션과 마찬가지로 다른 범용 "무시"사용할 수 있습니다.

var jsonResolver = new IgnorableSerializerContractResolver();
// ignore your specific property
jsonResolver.Ignore(typeof(Foo), "string2");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };

이 코드는 나에게 마법처럼 작용했다.

using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

    public PropertyRenameAndIgnoreSerializerContractResolver()
    {
        _ignores = new Dictionary<Type, HashSet<string>>();
        _renames = new Dictionary<Type, Dictionary<string, string>>();
    }

    public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
    {
        if (!_ignores.ContainsKey(type))
            _ignores[type] = new HashSet<string>();

        foreach (var prop in jsonPropertyNames)
            _ignores[type].Add(prop);
    }

    public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
    {
        if (!_renames.ContainsKey(type))
            _renames[type] = new Dictionary<string, string>();

        _renames[type][propertyName] = newJsonPropertyName;
    }

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

        if (IsIgnored(property.DeclaringType, property.PropertyName))
        {
            property.ShouldSerialize = i => false;
            property.Ignored = true;
        }

        if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
            property.PropertyName = newJsonPropertyName;

        return property;
    }

    private bool IsIgnored(Type type, string jsonPropertyName)
    {
        if (!_ignores.ContainsKey(type))
            return false;

        return _ignores[type].Contains(jsonPropertyName);
    }

    private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
    {
        Dictionary<string, string> renames;

        if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
        {
            newJsonPropertyName = null;
            return false;
        }

        return true;
    }
}

//Foo의 number2를 무시하는 예

public class Foo
{
public string number1 { get; set; }
public string number2 { get; set; }
public string number3 { get; set; }
}
    string Foojson = @"[
    {
        ""number1"": 1,
        ""number2"": 12345678901234567890,
        ""number3"": 3
    },
    {
        ""number1"": 9,
        ""number2"": 12345678901234567890,
        ""number3"": 8
    }
]";
var jsonResolverFoo = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolverFoo.IgnoreProperty(typeof(Foo), "number2");
var serializerSettingsFoo = new JsonSerializerSettings();
serializerSettingsFoo.ContractResolver = jsonResolverFoo;
var deserializedJsonFoo = JsonConvert.DeserializeObject<List<Foo>>(Foojson, serializerSettingsFoo);

/* 리소스 링크: https://blog.rsuter.com/advanced-newtonsoft-json-dynamically-rename-or-ignore-properties-without-changing-the-serialized-class/ */

drzaus 답변 추가:를 사용할 수 있습니다.DefaultContractResolver그는 …을 제안했다.한창일 때CreateProperty사용하다property.Ignored = true;대신property.ShouldSerialize, 당신이 통과했을 때, 그것은 좋다.JsonSerializerSettings에게DeserializeObject기능 또는SerializeObject기능.

대체 수단

ResponseAttribute에 모델 파라미터 또는 문자열 파라미터가 있는 경우

public class ResponseAttribute : Attribute { }

public class ModelItem
{
    [Response]
    public Guid Id { get; set; }
}

코드

public class CustomJsonSerializer : JsonSerializerSettings
{
    public CustomJsonSerializer()
    {
        ContractResolver = new CustomContractResolver();
    }

    public CustomJsonSerializer(params string[] members)
    {
        ContractResolver = new CustomContractResolver(members);
    }

    public class CustomContractResolver : DefaultContractResolver
    {
        public string[] Members { get; set; }
        public CustomContractResolver(params string[] _members)
        {
            Members = _members;
        }

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

            if (Members?.Length > 0)
                property.ShouldSerialize = instance => { return Members.Contains(member.Name); };
            else
                property.ShouldSerialize = instance => { return member.GetCustomAttribute<ResponseAttribute>() != null; };

            return property;
        }
    }
}

사용;

return new JsonResult(model, new CustomJsonSerializer());

또는

return new JsonResult(model, new CustomJsonSerializer("Id","Test","Test2"));

비슷한 것을 발견했습니다만, 클래스에는 리스트<>와 사전<>이 포함되어 있어, JSON 파일에 격납되어 있는 것에 의해서 덮어쓰면 안 됩니다.스크래치 오브젝트에 데이터를 로드하고 필요한 아이템을 꺼내는 것이 당시 찾을 수 있었던 다른 방법보다 쉬웠습니다.

그래서 이 예에서는 이런 거...

public class Foo
{
    public string string1 { get; set; }
    public string string2 { get; set; }
    public string string3 { get; set; }
}
List<Foo> foos = new List<Foo>();

List<Foo> tmp= JsonConvert.DeserializeObject<List<Foo>>(json);

foreach(Foo item in tmp)
{
    foos.string1 = tmp.string1;
    foos.string3 = tmp.string3;
}

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-6-0에 따르면

클래스에 표시되지 않는 JSON 속성은 무시됩니다.

언급URL : https://stackoverflow.com/questions/12754463/json-net-ignore-property-during-deserialization

반응형