简体   繁体   English

将JSON序列化为对象。 有些属性总是一样,有些则不同

[英]Dserialise JSON to object. Some properties always the same, some different

I am trying to build a function where a user can upload a json file. 我正在尝试构建一个用户可以上传json文件的功能。

Each row in the json file can have a different nr of properties(ie columns). json文件中的每一行都可以具有不同的nr属性(即列)。 5 of these properties are always the same so I want those to be deserialized to an object. 这些属性中的5个始终相同,因此我希望将其反序列化为对象。 The rest of the properties have to go into a dictionary or something. 其余属性必须放入字典或其他内容中。

Here is a json example: 这是一个json示例:

[{
        "Projekt": "Bakker Bouw Service",
        "Ruimte": "Hoofdgebouw",
        "Apparaat": {
            "project": "Bosboom001",
            "versie": "812"
        },
        "Apparaat naam": "",
        "Status": "Goedgekeurd",
        "Testname1": "",
        "Testname3": "2000-01-04T10:37:00+01:00",
        "Testname7": "2001-01-03T00:00:00+01:00"
    }, {
        "Projekt": "Bakker Bouw Service",
        "Ruimte": "Hoofdgebouw",
        "Apparaat": {
            "project": "Vlaams003",
            "versie": "713"
        },
        "Apparaat naam": "",
        "Status": "Goedgekeurd",
        "Testname1": "Slecht",
        "Testname7": "2000-01-04T10:37:00+01:00",
        "Testname9": "2001-01-03T00:00:00+01:00",
        "Testname16": "18MOhm",
        "Testname23": "OK"
    }, {
        "Projekt": "Bakker Bouw Service",
        "Ruimte": "Hoofdgebouw",
        "Apparaat": {
            "project": "Vlaams017",
            "versie": "73"
        },
        "Apparaat naam": "GDR34Z5",
        "Status": "Afgekeurd",
        "Testname7": "2000-01-04T10:37:00+01:00",
        "Testname10": "0,012mA",
        "Testname16": "200MOhm",
        "Testname23": "200MOhm",
        "Testname25": "Afgekeurd",
        "Testname31": "0,01mA"
    }
]

Here is the class to deserialze to: 这是要反序列化的类:

public class KeuringRegel
{
    public string Projekt { get; set; }
    public string Ruimte { get; set; }
    public Apparaat Apparaat { get; set; }
    [JsonProperty(PropertyName = "Apparaat naam")]
    public string Apparaatnaam { get; set; }
    public string Status { get; set; }
    public Dictionary<string, object> testNames { get; set; }
}

public class Apparaat
{
    public string project { get; set; }
    public string versie { get; set; }
}

And here is the controller 这是控制器

public IActionResult Upload(IFormFile file)
    {
        string fileContent = null;
        using (var reader = new StreamReader(file.OpenReadStream()))
        {
            fileContent = reader.ReadToEnd();
        }
        List<KeuringRegel> keuringRegelList = JsonConvert.DeserializeObject<List<KeuringRegel>>(fileContent);
        //More stuff here
    }

The json successfully deserializes but the testNames value is always null. json成功反序列化,但testNames值始终为null。 I understand why, because there is no testNames property in the Json file. 我了解原因,因为Json文件中没有testNames属性。 However, how do I achieve what I want? 但是,我如何实现自己想要的? I am no Json expert. 我不是Json专家。

One way you can do this, assuming that there is only testNameNNNN entries as supplemental values, is to use the JsonExtensionDataAttribute like this: 假设只有 testNameNNNN条目作为补充值,您可以采用以下方法来执行此操作,即使用JsonExtensionDataAttribute

public class KeuringRegel
{
    public string Projekt { get; set; }
    public string Ruimte { get; set; }
    public Apparaat Apparaat { get; set; }
    [JsonProperty(PropertyName = "Apparaat naam")]
    public string Apparaatnaam { get; set; }
    public string Status { get; set; }
    [JsonExtensionData()]
    public Dictionary<string, object> testNames { get; set; }
}

This will give you the values whos don't fall into one of the other properties: 这将为您提供不属于其他属性之一的值:

在此处输入图片说明

It's a bit of a "blunt instrument" but you could always perform some post-processing on the returned instances of KeuringRegel to remove any errant entries from testNames (ie things that don't match the pattern testNameNNNN ). 这有点“笨拙”,但是您始终可以对返回的KeuringRegel实例执行一些后处理,以从KeuringRegel中删除所有错误条目(即与testNameNNNN模式不匹配的testNameNNNN )。

If your JSON does contain things that don't match the pattern testNameNNNN which would therefore get included, you could implement a custom class for the testNames property: 如果您的JSON 确实包含与testNameNNNN模式不匹配的内容, testNameNNNN其包含在内,则可testNames属性实现一个自定义类:

public class KeuringRegel
{
    public string Projekt { get; set; }
    public string Ruimte { get; set; }
    public Apparaat Apparaat { get; set; }
    [JsonProperty(PropertyName = "Apparaat naam")]
    public string Apparaatnaam { get; set; }
    public string Status { get; set; }
    [JsonExtensionData()]
    public TestNames testNames { get; set; }
}

public class TestNames : Dictionary<string, object>
{
    public new void Add(string key, object value)
    {
        if (key.StartsWith("testname", StringComparison.OrdinalIgnoreCase))
        {
            base.Add(key, value);
        }
    }
}

This will check each item that is added to the testNames dictionary and prevent its addition if (as in my comment where I had an item in the JSON of "badgerBadgetCatCat": 3 ) it doesn't match the pattern. 这将检查添加到testNames词典中的每个项目,并防止其添加(例如,在我的评论中,我在JSON中的"badgerBadgetCatCat": 3 )不匹配该模式。

Here u are full example 这是完整的例子

internal class Program
    {
        private static void Main(string[] args)
        {
            var str = @"[{
        ""Projekt"": ""Bakker Bouw Service"",
        ""Ruimte"": ""Hoofdgebouw"",
        ""Apparaat"": {
            ""project"": ""Bosboom001"",
            ""versie"": ""812""
        },
        ""Apparaat naam"": """",
        ""Status"": ""Goedgekeurd"",
        ""Testname1"": """",
        ""Testname3"": ""2000-01-04T10:37:00+01:00"",
        ""Testname7"": ""2001-01-03T00:00:00+01:00""
    }, {
        ""Projekt"": ""Bakker Bouw Service"",
        ""Ruimte"": ""Hoofdgebouw"",
        ""Apparaat"": {
            ""project"": ""Vlaams003"",
            ""versie"": ""713""
        },
        ""Apparaat naam"": """",
        ""Status"": ""Goedgekeurd"",
        ""Testname1"": ""Slecht"",
        ""Testname7"": ""2000-01-04T10:37:00+01:00"",
        ""Testname9"": ""2001-01-03T00:00:00+01:00"",
        ""Testname16"": ""18MOhm"",
        ""Testname23"": ""OK""
    }, {
        ""Projekt"": ""Bakker Bouw Service"",
        ""Ruimte"": ""Hoofdgebouw"",
        ""Apparaat"": {
            ""project"": ""Vlaams017"",
            ""versie"": ""73""
        },
        ""Apparaat naam"": ""GDR34Z5"",
        ""Status"": ""Afgekeurd"",
        ""Testname7"": ""2000-01-04T10:37:00+01:00"",
        ""Testname10"": ""0,012mA"",
        ""Testname16"": ""200MOhm"",
        ""Testname23"": ""200MOhm"",
        ""Testname25"": ""Afgekeurd"",
        ""Testname31"": ""0,01mA""
    }
]";

            var sw = Stopwatch.StartNew();

            var result = Mapper.Map(str);


            sw.Stop();
            Console.WriteLine($"Deserialized at {sw.ElapsedMilliseconds} ms ({sw.ElapsedTicks} tiks)");
        }

        public static class Mapper
        {
            static Mapper()
            {
                List<string> names = new List<string>();
                IEnumerable<PropertyInfo> p = typeof(KeuringRegel).GetProperties().Where(c => c.CanRead && c.CanWrite);
                foreach (var propertyInfo in p)
                {
                    var attr = propertyInfo.GetCustomAttribute<JsonPropertyAttribute>();
                    names.Add(attr != null ? attr.PropertyName : propertyInfo.Name);
                }

                Properties = names.ToArray();
            }


            private static string[] Properties { get; }



            public static KeuringRegel[] Map(string str)
            {
                var keuringRegels = JsonConvert.DeserializeObject<KeuringRegel[]>(str);
                var objs = JsonConvert.DeserializeObject(str) as IEnumerable;
                var objectList = new List<JObject>();
                foreach (JObject obj in objs)
                    objectList.Add(obj);

                for (var i = 0; i < keuringRegels.Length; i++)
                {
                    keuringRegels[i].testNames = new Dictionary<string, object>();
                    foreach (var p in objectList[i].Children().OfType<JProperty>().Where(c => !Properties.Contains(c.Name)).ToArray())
                        keuringRegels[i].testNames.Add(p.Name, p.Value);
                }

                return keuringRegels;
            }
        }


        public class KeuringRegel
        {
            public string Projekt { get; set; }
            public string Ruimte { get; set; }
            public Apparaat Apparaat { get; set; }

            [JsonProperty(PropertyName = "Apparaat naam")]
            public string Apparaatnaam { get; set; }

            public string Status { get; set; }
            public Dictionary<string, object> testNames { get; set; }
        }

        public class Apparaat
        {
            public string project { get; set; }
            public string versie { get; set; }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM