如何指示自定义JSON.. NET JsonConverter来识别一个特定的属性已经在上游序列化了



我有点为难。我有一个System.Security.Claims.Claim的集合,Claim的构造函数要求value参数包含一个字符串。特定声明的值需要是包含JObjectJArray,并且我可以很容易地在创建过程中遍走我的结构并构建我需要构建的内容,但我不知道如何指示Serializer将其手从中移开特定声明。

string content = await response.Content.ReadAsStringAsync();
JObject json = JObject.Parse(content);
List<JObject> foos = new List<JObject>();
var foosComingFromSomewhereElseWithADifferentStructure = json["foos"];
bool first = true;
foreach (var _foo in foosComingFromSomewhereElseWithADifferentStructure.Children<JObject>())
{
   JObject foo = new JObject();
   string bar = (string)_foo["quux"].Value<JToken>();
   string baz = (string)_foo["inga"].Value<JToken>();
   foo.Add("Baz", baz);
   foo.Add("Bar", bar);
   foos.Add(foo);
}
claims.Add(new Claim("FooBar", (string)JsonConvert.SerializeObject(foos)));

在上面的代码块运行之后,我继续处理,然后我需要通过Json序列化器传递整个enchilada(我的序列化本质上需要多次执行)

所以如果我要现在需要通过另一个JSON传递索赔列表。. NET JsonConverter,我如何最好地声明序列化器保持它的手离开FooBar,因为它的值已经准备为JSON?

现在,我的序列化程序输出:

{
   "FooBar": "[{"Baz"":"inga","Bar":"quux"}]
}

当我需要它吐出

{
   "FooBar": [{"Baz":"inga","Bar":"quux"}]
}

要做这种事情,您需要自定义JsonConverter。转换器可以检测索赔值是否为JSON,如果是,则使用JRaw将已经准备好的值插入JSON主体的其余部分,而不进行转义或更改。另一方面,如果转换器接收到的是一个对象而不是声明值的字符串(如果值是未转义的JSON就会这样),那么在放入声明对象之前,它必须将该对象重新序列化为JSON。

像这样可以工作:

class ClaimConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(System.Security.Claims.Claim));
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var claim = (System.Security.Claims.Claim)value;
        JObject jo = new JObject();
        jo.Add("Type", claim.Type);
        jo.Add("Value", IsJson(claim.Value) ? new JRaw(claim.Value) : new JValue(claim.Value));
        jo.Add("ValueType", claim.ValueType);
        jo.Add("Issuer", claim.Issuer);
        jo.Add("OriginalIssuer", claim.OriginalIssuer);
        jo.WriteTo(writer);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        string type = (string)jo["Type"];
        JToken token = jo["Value"];
        string value = token.Type == JTokenType.String ? (string)token : token.ToString(Formatting.None);
        string valueType = (string)jo["ValueType"];
        string issuer = (string)jo["Issuer"];
        string originalIssuer = (string)jo["OriginalIssuer"];
        return new Claim(type, value, valueType, issuer, originalIssuer);
    }
    private bool IsJson(string val)
    {
        return (val != null &&
                (val.StartsWith("[") && val.EndsWith("]")) ||
                (val.StartsWith("{") && val.EndsWith("}")));
    }
}
演示:

class Program
{
    static void Main(string[] args)
    {
        var someJson = @"
        [
            { ""quux"": ""abc"", ""inga"": ""def"" },
            { ""quux"": ""pqr"", ""inga"": ""stu"" }
        ]";
        JArray foosComingFromSomewhereElse = JArray.Parse(someJson);
        List<JObject> foos = new List<JObject>();
        foreach (var _foo in foosComingFromSomewhereElse.Children<JObject>())
        {
            JObject foo = new JObject();
            string bar = (string)_foo["quux"].Value<JToken>();
            string baz = (string)_foo["inga"].Value<JToken>();
            foo.Add("Baz", baz);
            foo.Add("Bar", bar);
            foos.Add(foo);
        }
        Console.WriteLine("--- Original FooBar JSON ---");
        string foobarJson = JsonConvert.SerializeObject(foos);
        Console.WriteLine(foobarJson);
        Console.WriteLine();
        List<Claim> claims = new List<Claim>();
        claims.Add(new Claim("FooBar", foobarJson));
        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            Converters = new List<JsonConverter> { new ClaimConverter() },
            Formatting = Formatting.Indented
        };
        Console.WriteLine("--- Serialized list of claims ---");
        string claimsJson = JsonConvert.SerializeObject(claims, settings);
        Console.WriteLine(claimsJson);
        Console.WriteLine();
        Console.WriteLine("--- Deserialized claim values ---");
        claims = JsonConvert.DeserializeObject<List<Claim>>(claimsJson, settings);
        foreach(Claim claim in claims)
            Console.WriteLine(claim.Value);
    }
}
输出:

--- Original FooBar JSON ---
[{"Baz":"def","Bar":"abc"},{"Baz":"stu","Bar":"pqr"}]
--- Serialized list of claims ---
[
  {
    "Type": "FooBar",
    "Value": [{"Baz":"def","Bar":"abc"},{"Baz":"stu","Bar":"pqr"}],
    "ValueType": "http://www.w3.org/2001/XMLSchema#string",
    "Issuer": "LOCAL AUTHORITY",
    "OriginalIssuer": "LOCAL AUTHORITY"
  }
]
--- Deserialized claim values ---
[{"Baz":"def","Bar":"abc"},{"Baz":"stu","Bar":"pqr"}]

相关内容

  • 没有找到相关文章

最新更新