繁体   English   中英

JSON.NET 反序列化器返回 Null

[英]JSON.NET Deserializer is returning Null

编辑:它与 try/catch return null 语句无关。 我已经调试并观看了它并确保它不会进入那个 catch 块。 我什至评论了它,但无济于事。

我很累为我的应用程序构建配置管理器。 本质上,我有某些变量需要存储在 JSON 文件中并在应用程序启动期间读取,以便知道某些值。

对于其中一些配置变量,我将允许用户覆盖默认值,因此如果“用户”键具有非空字符串,我将使用它。 如果没有用户密钥或有空字符串,我将使用默认值。 为了满足这个要求,我编写了“AllowUserConfig”和“CoalesceUserDefault”方法来解决这个问题。

此时,我有一个 JSON 文件(如下)。 我复制了数据并作为一个类 JSONConfig 粘贴到 Visual Studio 中。 然后我有一个 ConfigManager 文件来完成真正的工作,我的 program.cs 调用 ConfigManager 以使用 DeserializeConfigVariables 方法读取配置文件(位于正确的位置),并从中创建一个 JSONConfig 对象。

话虽如此, DeserializeConfigVariables 中的 JSONConfig 对象将作为 null 返回(在configVariables = serializer.Deserialize<JSONConfig>(jsonReader); )。 有什么我想念的吗。 我已经把每件事都翻了一百遍,但看不出我做错了什么。

任何和所有帮助将不胜感激。

这是我的 JSON:

{
  "format": {
     "date": {
        "default": "yyyyMMdd",
        "user": ""
     },
     "month_year": {
        "default": "MM_YYYY",
        "user": ""
     }
  },
  "placeholders": {
     "current_date": "{date}",
     "month_year": "{month_year}",
     "last_monday": "{prev_monday}",
     "next_monday": "{next_monday}"
  },
  "resource_locations": {
     "directories": {
        "root_working": {
           "default": "C:\\ALL",
           "user": ""
        },
        "exports": {
           "default": "C:\\ALL\\Exports",
           "user": ""
        },
        "completed_exports": {
           "default": "C:\\ALL\\Done",
           "user": ""
        },
        "archived": {
           "default": "C:\\ALL\\Archives",
           "user": ""
        }
     },
     "compression": {
        "filename": {
           "default": "{next_monday}_daily_{date}.zip",
           "user": ""
        }
     },
     "logging": {
        "directory": "logs",
        "process_filename": "activity_log_{month_year}.log",
        "process_error_filename": "errors.log",
        "system_error_filename": "sys_errors.log"
     }
  }
}

这是我通过在 Visual Studio 中复制和粘贴 JSON 作为类创建的 JSONConfig 类:

using System;
using Newtonsoft.Json;

namespace Config
{

   public class JSONConfig
   {
       public RootObject ConfigVariables { get; set; }
   }

   public class RootObject
   {
       public Format format { get; set; }
       public Placeholders placeholders { get; set; }
       public Resource_Locations resource_locations { get; set; }
   }

   public class Format
   {
       public Date date { get; set; }
       public Month_Year month_year { get; set; }
   }

   public class Date
   {
       public string _default { get; set; }
       public string user { get; set; }
   }

   public class Month_Year
   {
       public string _default { get; set; }
       public string user { get; set; }
   }

   public class Placeholders
   {
       public string current_date { get; set; }
       public string month_year { get; set; }
       public string last_monday { get; set; }
       public string next_monday { get; set; }
   }

   public class Resource_Locations
   {
       public Directories directories { get; set; }
       public Compression compression { get; set; }
       public Logging logging { get; set; }
   }

   public class Directories
   {
       public Root_Working root_working { get; set; }
       public Exports exports { get; set; }
       public Completed_Exports completed_exports { get; set; }
       public Archived archived { get; set; }
   }

   public class Root_Working
   {
       public string _default { get; set; }
       public string user { get; set; }
   }

   public class Exports
   {
       public string _default { get; set; }
       public string user { get; set; }
   }

   public class Completed_Exports
   {
       public string _default { get; set; }
       public string user { get; set; }
   }

   public class Archived
   {
       public string _default { get; set; }
       public string user { get; set; }
   }


   public class Compression
   {
       public Filename filename { get; set; }
   }

   public class Filename
   {
       public string _default { get; set; }
       public string user { get; set; }
   }


   public class Logging
   {
       public string directory { get; set; }
       public string process_filename { get; set; }
       public string process_error_filename { get; set; }
       public string system_error_filename { get; set; }
   }


}

然后,在我的 ConfigManager 文件中,我有以下内容:

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using Newtonsoft.Json;

namespace Config
{
   static class ConfigManager
   {
       // Assumes parent directory is bin.  Assumes config is sibling to bin.
       private static string _initialConfig = @"config\config.json";
       public static string ConfigPath() => Path.Combine(GetRootAppDir(), _initialConfig);


       public static string Parent(string directory)
       {
           string parentDirectory = Directory.GetParent(directory).FullName;
           return parentDirectory;
       }

       public static string GetRootAppDir()
       {
           return Parent(Parent(Directory.GetCurrentDirectory()));
       }

       public static JSONConfig DeserializeConfigVariables()
       {
           try
           {
               var configVariables = new JSONConfig();
               var serializer = new JsonSerializer();
               Console.WriteLine($"Config Path: {ConfigPath()}"); //testing
               using (var reader = new StreamReader(ConfigPath()))
               using (var jsonReader = new JsonTextReader(reader))
               {
                   configVariables = serializer.Deserialize<JSONConfig>(jsonReader);
               }

               return configVariables;
           }
           catch (System.IO.DirectoryNotFoundException ex)
           {
               Console.WriteLine(ex.Message);
               return null;
           }

       }
       public static bool AllowUserConfig(object configVariable)
       {
           string userFieldName = "user";
           var objType = configVariable.GetType();
           return objType.GetMethod(userFieldName) != null;
       }

       public static string CoalesceUserDefault(dynamic configVariable)
       {
           if (AllowUserConfig(configVariable))
           {
               if (!(String.IsNullOrEmpty(configVariable.user)))
               {
                   return configVariable.user;
               }
           }
           return configVariable._default;
       }

   }
}

您的 Json 不包含根中名为ConfigVariable的属性,如类JSONConfig定义的JSONConfig (您尝试反序列化的类型)。

如果您检查,Json 符合RootObject的定义。 你应该反序列化类RootObject.You的实例,可以把它分配给ConfigVariable的实例的属性JsonConfig如果你的目的是将配置保存在JsonConfig的实例。

configVariables.ConfigVariables  = serializer.Deserialize<RootObject>(jsonReader);

希望,对你有帮助。

您可以添加yourjsonfile.json文件,例如:-

yourjsonfile.json

    {
      "key1": "value1",
      "key2": "value2",
     "ConnectionStrings": {
          "$ref": "anotherjsonfile.json#"
       }
    }

另一个jsonfile.json

{
     "key2": "value4"
}

确保您的jsonfile.json 和anotherjsonfile.json 文件属性将“复制到输出目录”设置为“始终复制”。

yourjsonfile.json和 anotherjsonfile.json 文件中查找值, yourjsonfile.json所示 -

var builder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    IConfiguration configuration = builder.Build();

    string GetValue1 = configuration.GetSection("key1").Value;
    string GetValue2 = configuration.GetSection("key2").Value;

     var builder1 = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(configuration.GetConnectionString("$ref").Replace("#", ""), optional: true, reloadOnChange: true);
    IConfiguration configuration1 = builder1.Build();

    GetValue2 = (configuration1.GetSection("key2").Value) != null ? configuration1.GetSection("key2").Value : GetValue2;

谢谢!!!

您需要将 json 反序列化为RootObject ,而不是JSONConfig

configVariables = serializer.Deserialize<RootObject>(jsonReader);

您的 json 具有三个根对象, FormatPlaceholdersResourceLocations ……但是您用来将 json 反序列化为的类只有一个对象……并且不匹配。

您可以随时使用 www.json2csharp.com,将您的 json 粘贴到那里,然后查看您需要反序列化到哪个对象(base 始终是 RootObject 那里)。

如何使用 JSONConfig 类

如果你真的想使用 JSONConfig 来反序列化你的 json,那么你需要稍微修改一下你的 JSON。 您需要将另一个根元素ConfigVariables添加到 json。

{ "ConfigVariables" :
 {
   "format": {
      "date": {
         "default": "yyyyMMdd",
         "user": ""
 ...

推荐

将反序列化 JSON 的方法也更改为更简单的过程。

public static RootObject DeserializeConfigVariables()
{
    return JsonConvert.DeserializeObject<RootObject>(File.ReadAllLines(ConfigPath()));
}

您的 Json 文件与您用来反实现它的对象结构不对应。 您的JsonConfig文件包含ConfigVariables属性,但 json 文件包含formatplaceholdersresource_locations属性, ConfigVariables属性应该在第二级。 尝试通过以下方式更新您的配置文件:

{

  "ConfigVariables": {
    "format": {
      "date": {
        "default": "yyyyMMdd",
        "user": ""
      },
      "month_year": {
        "default": "MM_YYYY",
        "user": ""
      }
    },
    "placeholders": {
      "current_date": "{date}",
      "month_year": "{month_year}",
      "last_monday": "{prev_monday}",
      "next_monday": "{next_monday}"
    },
    "resource_locations": {
      "directories": {
        "root_working": {
          "default": "C:\\ALL",
          "user": ""
        },
        "exports": {
          "default": "C:\\ALL\\Exports",
          "user": ""
        },
        "completed_exports": {
          "default": "C:\\ALL\\Done",
          "user": ""
        },
        "archived": {
          "default": "C:\\ALL\\Archives",
          "user": ""
        }
      },
      "compression": {
        "filename": {
          "default": "{next_monday}_daily_{date}.zip",
          "user": ""
        }
      },
      "logging": {
        "directory": "logs",
        "process_filename": "activity_log_{month_year}.log",
        "process_error_filename": "errors.log",
        "system_error_filename": "sys_errors.log"
      }
    }
  }
}

它会解决你的问题。 顺便说一句,正如我所见,您在配置对象中以 json 样式命名了属性。 例如, resource_locations最好以常规方式命名属性并添加JsonProperty属性以进行正确映射。 例如

[JsonProperty('resource_locations')]
public ResourceLocations ResouceLocations { get; set; }

暂无
暂无

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

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