C# 用于数组和集合的自定义Newtonsoft JsonConverter,用于进一步操作

C# 用于数组和集合的自定义Newtonsoft JsonConverter,用于进一步操作,c#,.net-core,json.net,.net-core-2.2,C#,.net Core,Json.net,.net Core 2.2,我想对字符串数组(或IEnumerable)使用一个自定义JsonConverter,并对数组进行一些操作(实际上删除所有空字符串或空白字符串) 但是我已经陷入了ReadJson方法中,不知道如何正确获取字符串[] 我为简单字符串做了一个自定义转换器,在这里我检查了JsonToken.String。但是阵列有星光阵列和EndArray 有谁已经反序列化了他们的自定义字符串数组,可以帮我吗 更多详情: 我想要实现的是在模型绑定上集中或可选的字符串修剪(因此我不必在每个控制器中都这样做),并且模型

我想对字符串数组(或IEnumerable)使用一个自定义JsonConverter,并对数组进行一些操作(实际上删除所有空字符串或空白字符串)

但是我已经陷入了ReadJson方法中,不知道如何正确获取字符串[]

我为简单字符串做了一个自定义转换器,在这里我检查了JsonToken.String。但是阵列有星光阵列和EndArray

有谁已经反序列化了他们的自定义字符串数组,可以帮我吗


更多详情:

我想要实现的是在模型绑定上集中或可选的字符串修剪(因此我不必在每个控制器中都这样做),并且模型验证检查重复项会将“字符串”和“字符串”检测为重复项

作为JSONConverter,我正在尝试这样做(深入挖掘model bindign日志输出、.net核心文档、.net核心github代码使我认识到json转换器是最好的)

集中使用将在启动Json选项中配置:

  public void ConfigureServices(IServiceCollection services)
  {
    services
      .AddMvc()
      .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
      .AddJsonOptions
      (
        options => 
        {
          options.SerializerSettings.Converters.Add(new TrimmedStringConverter());
          options.SerializerSettings.Converters.Add(new CleanStringArrayConverter());
        }
      );
  }
每种型号的使用情况

  public class RequestModel
  {

    [JsonConverter(typeof(TrimmedStringConverter))]
    public string MyValue { get; set; }

    [JsonConverter(typeof(CleanStringArrayConverter))]
    public string[] Entries { get; set; }

  }
提供用于自动修剪模型绑定字符串的转换器。我只是加了些盐

  public class TrimmedStringConverter : JsonConverter
  {

    public bool EmptyStringsAsNull { get; }

    public TrimmedStringConverter()
    {
      EmptyStringsAsNull = true;
    }

    public TrimmedStringConverter(bool emptyStringsAsNull)
    {
      EmptyStringsAsNull = emptyStringsAsNull;
    }

    public override bool CanConvert(Type objectType)
    {
      return objectType == typeof(string);
    }

    private string CleanString(string str)
    {
      if (str == null) return null;

      str = str.Trim();

      if (str.Length == 0 && EmptyStringsAsNull) return null;

      return str;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {

      if (reader.TokenType == JsonToken.String)
      {
        //if (reader.Value != null)
          return CleanString(reader.Value as string);
      }

      return reader.Value;

    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
      var text = (string)value;
      if (text == null)
        writer.WriteNull();
      else
        writer.WriteValue(CleanString(text));
    }

  }
现在,我的模型在字符串[]中有空字符串或空字符串。我现在尝试在第二个转换器中自动删除它(或者在上面做相同操作的转换器中,但对于字符串数组、集合)

我就是不知道如何正确处理读卡器和序列化器的数组序列化/反序列化


这就是我取得的成绩(感谢Silvermind)。用于字符串数组的第二个转换器

首先,我还设法在CleanStringArrayConverter中使用全局注册的TrimmedStringConverter(查看附加的注释代码)。只要TrimmedStringConverter在全球范围内使用,并且CleanStringArrayConverter在每种型号的基础上使用,这种方法就有效。全局使用这两种方法会导致无限循环和服务器崩溃以及访问冲突异常

所以我把它改成了这个版本,在这个版本中,两者都可以在全球范围内并排注册

不幸的是,它只适用于阵列

一旦你们中的某个人发现了这段代码,可以使用它并分享改进吗

  public class CleanStringArrayConverter : JsonConverter
  {

    public bool TrimStrings { get; }
    public bool EmptyStringsAsNull { get; }
    public bool RemoveWhitespace { get; }
    public bool RemoveNulls { get; }
    public bool RemoveEmpty { get; }


    public CleanStringArrayConverter()
    {
      TrimStrings = true;
      EmptyStringsAsNull = true;
      RemoveWhitespace = true;
      RemoveNulls = true;
      RemoveEmpty = true;
    }

    public CleanStringArrayConverter(bool trimStrings = true, bool emptyStringsAsNull = true, bool removeWhitespace = true, bool removeEmpty = true, bool removeNulls = true)
    {
      TrimStrings = trimStrings;
      EmptyStringsAsNull = emptyStringsAsNull;
      RemoveWhitespace = removeWhitespace;
      RemoveNulls = removeNulls;
      RemoveEmpty = removeEmpty;
    }

    private string CleanString(string str)
    {
      if (str == null) return null;

      if (TrimStrings) str = str.Trim();

      if (str.Length == 0 && EmptyStringsAsNull) return null;

      return str;
    }

    private string[] CleanStringCollection(IEnumerable<string> strings)
    {
      if (strings == null) return null;

      return strings
        .Select(s => CleanString(s))
        .Where
        (
          s =>
          {
            if (s == null) return !RemoveNulls;
            else if (s.Equals(string.Empty)) return !RemoveEmpty;
            else if (string.IsNullOrWhiteSpace(s)) return !RemoveWhitespace;
            else return true;
          }
        )
        .ToArray();
    }

    public override bool CanConvert(Type objectType)
    {
      return objectType.IsArray && objectType.GetElementType() == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {

      string[] arr = null;            // use null as default value
      //string[] arr = new string[];  // use empty array as default value

      // deserialze the array
      if (reader.TokenType != JsonToken.Null)
      {
        if (reader.TokenType == JsonToken.StartArray)
        {
          // this one respects other registered converters (e.g. the TrimmedStringConverter)
          // but causes server crashes when used globally due to endless loops
          //arr = serializer.Deserialize<string[]>(reader);

          // this doesn't respect others!!!
          JToken token = JToken.Load(reader);
          arr = token.ToObject<string[]>();
        }
      }

      // clean up the array
      if (arr != null) arr = CleanStringCollection(arr);

      return arr;

    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

      string[] arr = (string[])value;

      if (value == null)
      {
        writer.WriteNull();
        return;
      }

      arr = CleanStringCollection(arr);

      // endless loops and server crashes!!!
      //serializer.Serialize(writer, arr);


      writer.WriteStartArray();
      string v;
      foreach(string s in arr)
      {
        v = CleanString(s);
        if (v == null)
            writer.WriteNull();
        else
            writer.WriteValue(v);
      }

      writer.WriteEndArray();
    }

  }
公共类CleanStringArrayConverter:JsonConverter
{
公共布尔字符串{get;}
公共bool EmptyStringsAsNull{get;}
公共布尔删除空白{get;}
公共bool RemoveNulls{get;}
公共bool removempty{get;}
公共CleanStringArrayConverter()
{
TrimStrings=true;
EmptyStringsAsNull=true;
RemoveWhitespace=true;
RemoveNulls=真;
removempty=真;
}
公共CleanStringArrayConverter(bool trimStrings=true,bool emptyStringsAsNull=true,bool removeWhitespace=true,bool removeEmpty=true,bool removeNulls=true)
{
TrimStrings=TrimStrings;
EmptyStringsAsNull=EmptyStringsAsNull;
RemoveWhitespace=RemoveWhitespace;
RemoveNulls=RemoveNulls;
removempty=removempty;
}
私有字符串CleanString(字符串str)
{
if(str==null)返回null;
if(TrimStrings)str=str.Trim();
if(str.Length==0&&EmptyStringsAsNull)返回null;
返回str;
}
私有字符串[]CleanStringCollection(IEnumerable字符串)
{
if(strings==null)返回null;
返回字符串
.选择(s=>CleanString)
哪里
(
s=>
{
如果(s==null)返回!RemoveNulls;
否则如果(s.Equals(string.Empty))返回!removempty;
else if(string.IsNullOrWhiteSpace)返回!removewitespace;
否则返回true;
}
)
.ToArray();
}
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType.IsArray&&objectType.GetElementType()==typeof(字符串);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
字符串[]arr=null;//使用null作为默认值
//string[]arr=new string[];//使用空数组作为默认值
//反序列化数组
if(reader.TokenType!=JsonToken.Null)
{
if(reader.TokenType==JsonToken.StartArray)
{
//这一项与其他注册转换器(例如TrimmedStringConverter)相关
//但由于无休止的循环,在全局使用时会导致服务器崩溃
//arr=序列化程序。反序列化(读取器);
//这不尊重别人!!!
JToken令牌=JToken.Load(读卡器);
arr=token.ToObject();
}
}
//清理阵列
如果(arr!=null)arr=CleanStringCollection(arr);
返回arr;
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
字符串[]arr=(字符串[])值;
如果(值==null)
{
WriteNull();
返回;
}
arr=清洁字符串集合(arr);
//无休止的循环和服务器崩溃!!!
//serializer.Serialize(writer,arr);
writer.writestarray();
字符串v;
foreach(arr中的字符串s)
{
v=清洁串;
如果(v==null)
WriteNull();
其他的
书面价值(v);
}
writer.WriteEndArray();
}
}

基本上是相同的想法:

internal sealed class TrimmedStringCollectionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsArray && objectType.GetElementType() == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (existingValue is null)
        {
             // Returning empty array???
             return new string[0];
        }

        var array = (string[])existingValue;
        return array.Where(s => !String.IsNullOrEmpty(s)).ToArray();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value);
    }
}

也许您也希望对编写部分执行同样的操作。

请编写代码……为什么不让newtonsoft解析json,然后删除空字符串呢?@AndréSanson是的,这正是我(不知何故)真正想做的。我想补充问题的更多细节。