无法通过 Action 参数将 JsonSerializerSetting 从一个程序集传递到另一个程序集

Trouble passing a JsonSerializerSetting from one assembly via an Action parameter to another assembly

使用 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 已正确设置,但反序列化完成时 'response' 对象中的所有值都为 null 或默认值。

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

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

我的第一个倾向是怀疑不可能 pass/use 来自一个程序集的 JsonSerializerSettings to/in 另一个以这种方式,一个静态对象作为动作的参数?

我可能做错了什么。

我提前向任何认为我的问题结构不正确、缺乏信息或以其他方式回答的人道歉,我正在努力遵守规则...

1。 JsonConvert returns 空值或默认值

您描述的那种导致您的 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 }

Incorrect mapping will result in nulls and defaults.


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();
    }
}

Make sure that you are properly mapping the object in the custom converter.

把它们放在一起...

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。组件之间转换器的可移植性

To be 100% certain that the converters will get passed along with your settings, you can always do something like this

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
    {
        ...
    }
}