【问题标题】:Trouble passing a JsonSerializerSetting from one assembly via an Action parameter to another assembly无法通过 Action 参数将 JsonSerializerSetting 从一个程序集传递到另一个程序集
【发布时间】:2017-11-05 03:50:55
【问题描述】:

使用 Json.Net,我试图将 JsonSerializerSettings 对象作为 Action 的参数之一传递。

SerializerSettings 在程序集 A 中:

public static class SerializerSettings
{
    public static readonly JsonSerializerSettings Jss = new JsonSerializerSettings
    {
        MissingMemberHandling = MissingMemberHandling.Error,
        NullValueHandling = NullValueHandling.Ignore,
        Converters = new List<JsonConverter>
           { new StringEnumConverter(), new NullStringConverter() }
    };
}

(NullStringConverter 只是一个继承自 JsonConverter 的自定义转换器)

为了简洁:

public class NullStringConverter : JsonConverter
{}

我可能没有使用最好或适当的术语来描述这一点,但是,然后从程序集 B 将下面定义的方法作为指向程序集 A 的指针传递,并在程序集 A 中调用它的参数,其中包括定义的 JsonSerializerSettings以上。

private static void Investigated<TRequest, TResponse>(string data, JsonSerializerSettings jss) where TRequest : IBaseRequest where TResponse : IBaseResponse
{
    if (string.IsNullOrEmpty(data) || jss == null)
        Console.WriteLine("Bad Data");
    else
    {
        var response = JsonConvert.DeserializeObject<TResponse>(data, jss);
    }
}

在调试器中,我看到数据字符串很好,jss 设置正确,但反序列化完成时“响应”对象中的所有值都为 null 或默认值。

如果我将相同的 JsonSerializerSettings 本地移动到程序集 B,则反序列化效果很好...

我什至尝试从传入的 JsonSerializerSettings 创建一个新的 JsonSerializerSettings,但它具有相同的 null/默认结果。

我的第一个倾向是怀疑不可能以这种方式将 JsonSerializerSettings 从一个程序集传递/使用到另一个程序集,将静态对象作为操作的参数?

我可能做错了什么。

如果有人觉得我的问题没有很好地形成、缺乏信息或在其他地方得到了回答,我会提前向任何人道歉,我正在努力遵守规则......

【问题讨论】:

  • 通常当您收到空响应时,这是因为您尝试将数据映射到的对象不匹配。您是否确认 TResponse 实际上已正确映射到您的数据?
  • 是的先生,从本地定义 JsonSerializer 并获得正确的结果确认我有一个正确映射的 TResponse 对象。
  • 我已经为你添加了一个更完整的答案。

标签: c# json.net .net-assembly


【解决方案1】:

1。 JsonConvert 返回空值或默认值

当您未正确映射对象时,会出现您描述的导致您的 JsonConvert.DeserializeObject() 方法返回具有空值或默认值的对象的那种症状。这是一个小例子来说明它。

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Bar
{
    public int BarId { get; set; }
    public string BarName { get; set; }
}

void Main()
{
    var foo = new Foo()
    {
        Id = 1,
        Name = "One"
    };  
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(foo);
    
    
    var bar = Newtonsoft.Json.JsonConvert.DeserializeObject<Bar>(json);
}

这是bar的结果:

bar = { BarId = 0, BarName = null }

不正确的映射会导致空值和默认值


2。使用自定义 JsonConverter 时要注意细节

进一步看上面的例子,当使用JsonConverter 时,您还必须注意映射,因为它更容易因小错别字或其他错误而产生相同类型的问题。

MyCustomJsonSerializerSettings

public static class MyCustomJsonSerializerSettings
{
    private static JsonSerializerSettings _jss;
    
    public static JsonSerializerSettings Jss
    {
        get { return _jss; }
        private set { _jss = value; }
    }
    
    static MyCustomJsonSerializerSettings()
    {
        _jss = new JsonSerializerSettings
        {
            MissingMemberHandling = MissingMemberHandling.Error,
            NullValueHandling = NullValueHandling.Ignore,
            Converters = new List<JsonConverter>
            {
                new FooToBarConverter()
            }
        };
    }
}

FooToBarConverter

public class FooToBarConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override void WriteJson(
        JsonWriter writer, 
        object value, 
        JsonSerializer serializer)
    {
        Foo foo = (Foo)value;
        JObject jo = new JObject();
        jo.Add("BarId", new JValue(foo.Id));     // make sure of your mapping!
        jo.Add("BarName", new JValue(foo.Name)); // make sure of your mapping!
        jo.WriteTo(writer);
    }

    public override object ReadJson(
        JsonReader reader, 
        Type objectType, 
        object existingValue, 
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

确保您在自定义转换器中正确映射对象。

把它们放在一起......

void Main()
{
    var foo = new Foo()
    {
        Id = 1,
        Name = "One"
    };  
    
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(foo);
    var bar = Newtonsoft.Json.JsonConvert.DeserializeObject<Bar>(json); // nulls/defaults
    
    JsonSerializerSettings jss = MyCustomJsonSerializerSettings.Jss;
    string json2 = Newtonsoft.Json.JsonConvert.SerializeObject(foo, jss); // note jss
    var bar2 = Newtonsoft.Json.JsonConvert.DeserializeObject<Bar>(json2); // as expected!
}

3。组件之间转换器的可移植性

要 100% 确定转换器会与您的设置一起传递,您可以随时执行类似的操作

public class MyCustomJsonSerializerSettings // not a static class
{
    private static JsonSerializerSettings _jss;
    
    public static JsonSerializerSettings Jss
    {
        get { return _jss; }
        private set { _jss = value; }
    }
    
    static MyCustomJsonSerializerSettings()
    {
        _jss = new JsonSerializerSettings { ... };
    }

    private class FooToBarConverter : JsonConverter // note that it is contained within
                                                    // the class
    {
        ...
    }
}

【讨论】:

  • 我明白了你的建议,我会再看一遍,但在反序列化正在发生的程序集中定义 JsonSerializer 设置时,结果正确,这向我证明了对象已正确映射
  • @axa 没问题。如果您对转换器有更具体的问题,您可以提出一个新问题。只是不要忘记提供链接
  • 好的,我要回去看看按照建议将 serializerSettings 字段更改为属性,我知道 json 可以特别适合这些
  • @axa - 还要查看最后添加的内容,以确保转换器包含在设置中。您在程序集周围传递它的方式可能会发生一些事情。
  • 是的,我将对这些项目中的每一个进行了解。感谢您抽出宝贵的时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多