应对JSON的嵌套C#类

发布于 2025-01-22 17:43:56 字数 2449 浏览 0 评论 0原文

以下是成功创建新的“工作代码”条目后,我会从REST API中获得的(稍微)删除的响应。我需要将响应当作某些课程,但我很难过。

作为参考,我正在使用.NET 3.5中的JSON.NET(在SQL Server 2008 R2中以SSIS脚本运行)来尝试我的避难所化。这是JSON-我显然无法控制它,因为它来自别人的API:

{
   "results":{
      "jobcodes":{
         "1":{
            "_status_code":200,
            "_status_message":"Created",
            "id":444444444,
            "assigned_to_all":false,
            "billable":true,
            "active":true,
            "type":"regular",
            "name":"1234 Main Street - Jackson"
         },
         "2":{
            "_status_code":200,
            "_status_message":"Created",
            "id":1234567890,
            "assigned_to_all":false,
            "billable":true,
            "active":true,
            "type":"regular",
            "name":"4321 Some Other Street - Jackson"
         }
      }
   }
}

在我的C#代码中,我确实有一个“ Job Code”类定义了,它仅部分将JSON值映射到属性 - 我对所有人都不感兴趣在返回给我的数据中:

[JsonObject]
class JobCode
{
    [JsonProperty("_status_code")]
    public string StatusCode { get; set; }
    [JsonProperty("_status_message")]
    public string StatusMessage { get; set; }
    [JsonProperty("id")]
    public string Id {get; set;}
    [JsonProperty("name")]
    public string Name { get; set; }

    //-------------------------------------------------------------------------------
    // Empty constructor for JSON serialization support
    //-------------------------------------------------------------------------------

    public JobCode() { }
}

我正在尝试通过此调用来对数据进行测试:

newResource = JsonConvert.DeserializeObject<JobCode>(jsonResponse);

其中jsonresponse是上面输出的代码。
当我执行代码时,“ newresource”总是以null为单位 - 这并不意外,因为我知道数据中实际上有多个作业代码,并且此代码试图将其验证为单个job copcode对象。我尝试创建一个名为jobcodes的新类,看起来像这样:

class JobCodes
{
    [JsonProperty("jobcodes")]
    public List<JobCode>_JobCodes { get; set; }
}

然后我尝试调用此(jobcodes而不是job Codcode):

newResource = JsonConvert.DeserializeObject<JobCodes>(jsonResponse);

但是问题坚持不懈 - 我的返回对象为null。 我认为,让我失望的是“ 1”和“ 2”标识符的存在。我不知道如何解释它们在我的对象设计中的存在和/或json.net类/属性属性(例如[jsonobject]),[jsonproperty]

等等 被证明太有效了。我已经用几个不同的验证器验证了JSON,所有这些都检查了 - 我不知道我在这里缺少什么。

最终,我想从JSON数据中返回lt; job Code&gt;,但我对实现这一目标所需要做的事情感到困惑。

Below is a (slightly) stripped down response I get from a REST API upon successful creation of a new "job code" entry. I need to deserialize the response into some classes, but I'm stumped.

For reference, I'm using JSON.NET in .NET 3.5 (running in a SSIS script in SQL Server 2008 R2) to attempt my deserialization. Here's the JSON - which I obviously have no control over as it's coming from someone else's API:

{
   "results":{
      "jobcodes":{
         "1":{
            "_status_code":200,
            "_status_message":"Created",
            "id":444444444,
            "assigned_to_all":false,
            "billable":true,
            "active":true,
            "type":"regular",
            "name":"1234 Main Street - Jackson"
         },
         "2":{
            "_status_code":200,
            "_status_message":"Created",
            "id":1234567890,
            "assigned_to_all":false,
            "billable":true,
            "active":true,
            "type":"regular",
            "name":"4321 Some Other Street - Jackson"
         }
      }
   }
}

In my C# code, I do have a "JobCode" class defined which only partially maps the JSON values to properties - I'm not interested in all of the data that's returned to me:

[JsonObject]
class JobCode
{
    [JsonProperty("_status_code")]
    public string StatusCode { get; set; }
    [JsonProperty("_status_message")]
    public string StatusMessage { get; set; }
    [JsonProperty("id")]
    public string Id {get; set;}
    [JsonProperty("name")]
    public string Name { get; set; }

    //-------------------------------------------------------------------------------
    // Empty constructor for JSON serialization support
    //-------------------------------------------------------------------------------

    public JobCode() { }
}

I'm attempting to deserialize the data via this call:

newResource = JsonConvert.DeserializeObject<JobCode>(jsonResponse);

Where jsonResponse is the code outputted above.
When I execute the code, "newResource" always comes back as null - which is not unexpected because I know that there are actually multiple job codes in the data and this code is trying to deserialize it into a single JobCode object. I tried creating a new class called JobCodes that looks like this:

class JobCodes
{
    [JsonProperty("jobcodes")]
    public List<JobCode>_JobCodes { get; set; }
}

And then I tried calling this (JobCodes instead of JobCode):

newResource = JsonConvert.DeserializeObject<JobCodes>(jsonResponse);

But the issue persists - my return object is null.
What's throwing me off, I think, is the presence of the "1" and "2" identifiers. I don't know how to account for their presence in my object design and/or usage of the JSON.NET class / property attributes like [JsonObject],[JsonProperty], etc.

When I run the JSON data through JSON2CSharp, it constructs some weird-looking classes, so that hasn't proven too effective. I've validated the JSON with several different validators and it all checks out–I just don't know what I'm missing here.

Ultimately, I'd like to return a List<JobCode> from the JSON data, but I'm stumped on what I need to do to make that happen.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你不是我要的菜∠ 2025-01-29 17:43:57

您的问题是双重的:

  1. 您没有在根级别定义的类。类结构需要匹配整个 JSON,您不能仅仅从中间进行挑选。
  2. 只要您有一个可以更改键的对象,就需要使用字典&lt; string,t&gt;。普通课程将不起作用; lt&lt; t&gt;也不会。

这样做这样的课程:

class RootObject
{
    [JsonProperty("results")]
    public Results Results { get; set; }
}

class Results
{
    [JsonProperty("jobcodes")]
    public Dictionary<string, JobCode> JobCodes { get; set; }
}

class JobCode
{
    [JsonProperty("_status_code")]
    public string StatusCode { get; set; }
    [JsonProperty("_status_message")]
    public string StatusMessage { get; set; }
    [JsonProperty("id")]
    public string Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
}

然后,这样的选择:

RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

在此处工作演示

Your problem is twofold:

  1. You don't have a class defined at the root level. The class structure needs to match the entire JSON, you can't just deserialize from the middle.
  2. Whenever you have an object whose keys can change, you need to use a Dictionary<string, T>. A regular class won't work for that; neither will a List<T>.

Make your classes like this:

class RootObject
{
    [JsonProperty("results")]
    public Results Results { get; set; }
}

class Results
{
    [JsonProperty("jobcodes")]
    public Dictionary<string, JobCode> JobCodes { get; set; }
}

class JobCode
{
    [JsonProperty("_status_code")]
    public string StatusCode { get; set; }
    [JsonProperty("_status_message")]
    public string StatusMessage { get; set; }
    [JsonProperty("id")]
    public string Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
}

Then, deserialize like this:

RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

Working demo here

尘世孤行 2025-01-29 17:43:57

因为您无法更改JSON的方案,并且无法设置属性恒定数量,所以我建议您使用jobign

var jobject = JObject.Parse(json);

var results = jobject["results"];
var jobcodes = results["jobcodes"];

var output = jobcodes.Children<JProperty>()
                     .Select(prop => prop.Value.ToObject<JobCode>())
                     .ToList();

警告:代码假设,JSON始终处于适当的架构中。您还应该处理无效的架构(例如,属性不是job Code方案)。

Because you can't change the scheme of JSON, and you can't set constant No. of properties, I'd suggest you to use JObject

var jobject = JObject.Parse(json);

var results = jobject["results"];
var jobcodes = results["jobcodes"];

var output = jobcodes.Children<JProperty>()
                     .Select(prop => prop.Value.ToObject<JobCode>())
                     .ToList();

Warning: code assumes, that JSON is always in proper schema. You should also handle invalid schema (for example where property is not of JobCode scheme).

┼── 2025-01-29 17:43:57

您还可以将JSON的json归为目标类的对象,然后按照正常读取其属性:

var obj = DeSerializeFromStrToObj<ClassToSerialize>(jsonStr);
Console.WriteLine($"Property: {obj.Property}");

其中deleializefromstrtoobj是一种自定义类,可利用反思来实例化目标类的对象:

    public static T DeSerializeFromStrToObj<T>(string json)
    {
        try
        {
            var o = (T)Activator.CreateInstance(typeof(T));

            try
            {
                var jsonDict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);

                var props = o.GetType().GetProperties();

                if (props == null || props.Length == 0)
                {
                    Debug.WriteLine($"Error: properties from target class '{typeof(T)}' could not be read using reflection");
                    return default;
                }

                if (jsonDict.Count != props.Length)
                {
                    Debug.WriteLine($"Error: number of json lines ({jsonDict.Count}) should be the same as number of properties ({props.Length})of our class '{typeof(T)}'");
                    return default;
                }

                foreach (var prop in props)
                {
                    if (prop == null)
                    {
                        Debug.WriteLine($"Error: there was a prop='null' in our target class '{typeof(T)}'");
                        return default;
                    }

                    if (!jsonDict.ContainsKey(prop.Name))
                    {
                        Debug.WriteLine($"Error: jsonStr does not refer to target class '{typeof(T)}'");
                        return default;
                    }

                    var value = jsonDict[prop.Name];
                    Type t = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                    object safeValue = value ?? Convert.ChangeType(value, t);
                    prop.SetValue(o, safeValue, null); // initialize property
                }
                return o;
            }
            catch (Exception e2)
            {
                Debug.WriteLine(e2.Message);
                return o;
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            return default;
        }
    }

在我对类似问题的增强答案中可以找到一个完整的工作示例课程,在这里

You can also deserialize your json to an object of your target class, and then read its properties as per normal:

var obj = DeSerializeFromStrToObj<ClassToSerialize>(jsonStr);
Console.WriteLine(
quot;Property: {obj.Property}");

where DeSerializeFromStrToObj is a custom class that makes use of reflection to instantiate an object of a targeted class:

    public static T DeSerializeFromStrToObj<T>(string json)
    {
        try
        {
            var o = (T)Activator.CreateInstance(typeof(T));

            try
            {
                var jsonDict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);

                var props = o.GetType().GetProperties();

                if (props == null || props.Length == 0)
                {
                    Debug.WriteLine(
quot;Error: properties from target class '{typeof(T)}' could not be read using reflection");
                    return default;
                }

                if (jsonDict.Count != props.Length)
                {
                    Debug.WriteLine(
quot;Error: number of json lines ({jsonDict.Count}) should be the same as number of properties ({props.Length})of our class '{typeof(T)}'");
                    return default;
                }

                foreach (var prop in props)
                {
                    if (prop == null)
                    {
                        Debug.WriteLine(
quot;Error: there was a prop='null' in our target class '{typeof(T)}'");
                        return default;
                    }

                    if (!jsonDict.ContainsKey(prop.Name))
                    {
                        Debug.WriteLine(
quot;Error: jsonStr does not refer to target class '{typeof(T)}'");
                        return default;
                    }

                    var value = jsonDict[prop.Name];
                    Type t = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                    object safeValue = value ?? Convert.ChangeType(value, t);
                    prop.SetValue(o, safeValue, null); // initialize property
                }
                return o;
            }
            catch (Exception e2)
            {
                Debug.WriteLine(e2.Message);
                return o;
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            return default;
        }
    }

A complete working example class can be found in my enhanced answer to a similar question, here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文