Я хочу использовать пользовательский JsonConverter для строковых массивов (или IEnumerable) и выполнять некоторые манипуляции с массивом (фактически удаляя все строки, которые являются нулевыми или пробельными).
Но я уже застрял в ReadJsonметод, не зная, как правильно получить строку [].
Я сделал пользовательский конвертер для простых строк, где проверил JsonToken.String.Но у массивов есть StartArray и EndArray ...
Кто-нибудь, кто уже де / сериализовал свои пользовательские строковые массивы и может мне помочь?
Подробнее:
ЧтоЯ хочу добиться централизованного или необязательного обрезания строки при привязке модели (поэтому мне не нужно это делать на каждом контроллере), и проверка правильности модели на наличие дубликатов выявила бы «строку» и «строку» как дубликат.
Я пытаюсь сделать это как JsonConverters (выкапывая вывод журнала привязки модели, документы .net core, код github .net core, я понял, что конвертер json лучше всего).
Централизованное использованиебыть сконфигурирован в StartUp Json Options:
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).Второй преобразователь для строковых массивов.
Сначала мне удалось использовать глобально зарегистрированный TrimmedStringConverter в CleanStringArrayConverter (проверьте дополнительный код с комментариями).Это работало до тех пор, пока TrimmedStringConverter использовался глобально, а CleanStringArrayConverter использовался для каждой модели.Использование обоих глобально вызывает бесконечные циклы и СЕРВЕРНЫЕ АВАРИИ с исключением Access Violation.
Поэтому я изменил его на эту версию, где оба могут быть зарегистрированы глобально рядом.
К сожалению, это будет работать только длямассивы.
Может ли кто-нибудь из вас найти этот код, использовать его и поделиться своими улучшениями?
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();
}
}