【问题标题】:C# JsonConverter JSONArray to string w/ separator and backC# JsonConverter JSONArray 到带分隔符的字符串并返回
【发布时间】:2017-11-17 20:01:54
【问题描述】:

我想实现一个自定义的 JsonConverter 来使用,

    [JsonConverter(typeof(ArrayString))]
    public string ServiceCodes { get; set; }

目的是将 JSON 数组转换为带分隔符的字符串,例如, ["this", "is", "my", "json", "array"] 应该变成 "this;is;my;json;array" (或任何分隔符)。同样,反过来应该是可能的。

我很难理解覆盖JsonConverterWriteJson 方法。

为了提供一些上下文,我 ServiceCodes 是实体上的一个属性(我使用的是 EF6)。我认为做我要求的事情比其他一对多的实现更容易。但是,我有一个问题是何时调用 JsonConverter?

我只希望 get 在 getter 需要 json 时提供 json,即当包含此属性的对象从我的 API 作为 JSON 返回时。例如,我不希望在编写 LINQ 时调用此转换器。

任何帮助将不胜感激,谢谢。

编辑 - 添加信息

这是类和一些 moc 数据。

    [ComplexType]
    public class TerminalDuties
    {
        public string TerminalCode { get; set; }

        public string TransportationCode { get; set; }

        [JsonConverter(typeof(ArrayString))]
        public string ServiceCodes { get; set; }
    }

"Origin": { "TerminalCode": "MIA", "TransportationCode": "GT", "ServiceCodes": ["WH", "HL"] }

我尝试了@felix-b 的答案,但它不是映射。对象为空。我在 ArrayString 类中有断点,但它们没有被击中。大概它没有尝试映射,因为该属性是一个字符串。解决方法是什么?

这是它在我的 Web API 控制器中的公开方式(从 ApiController 继承)

    [HttpPost]
    public void DoStuff([FromBody]Thing t)
    {
        someMngr.Add(t);
    }

    public class Thing : ParentClass
    {
        properties...
        public TerminalDuties Origin { get; set; }
    }

【问题讨论】:

  • 如果您希望从"this;is;an;array" 转换为["this", "is", "an", "array"],您可能需要编写一个自定义转换器来完成它(也许只是一个简单的string.Split..?)。 JsonConverter 属性仅在使用 Json 序列化程序转换对象时使用。从了解您使用的 Web 框架开始 - ASP.NET MVC、ASP.NET Web API 等?然后缩小搜索范围,了解如何序列化 API 方法的响应。
  • 谢谢你,@GeoffJames!我现在在 ASP.NET Web API 2 中。是的,我打算使用 string.Split 和 string.Join 来实现。我只是想在 JsonConverter 方法中做到这一点。
  • 不用担心。我会一步一步来。将其剥离回您开始的位置(在属性等之前),并首先让它在请求中返回 Json。然后,当您确定它正常工作时,您可以开始使用您的自定义转换器。否则你试图一次解决许多问题,并且不能总是确定你刚刚改变的原因/结果等。
  • [JsonConverter(typeof(ArrayString))] 不正确;请改用 [JsonConverter(typeof(ArrayString), ';')]。由于您在问题中提到了“任何分隔符”,因此我将其设置为可配置的。
  • 更改了答案,以便 [JsonConverter(typeof(ArrayString))] 现在也可以正常工作,使用分号作为默认分隔符。

标签: c# arrays string json.net


【解决方案1】:

使用 .NET Framework 4.6.1、ASP.NET Web API 2、Entity Framework 6.1.3、Newtonsoft.Json 10.0.3 测试。

更新

我的答案最初要求指定[JsonConverter(typeof(ArrayString), ';')],而不是问题中的[JsonConverter(typeof(ArrayString))]

我为转换器类添加了默认构造函数,因此分隔符配置是可选的,如果不指定将使用分号。现在[JsonConverter(typeof(ArrayString))] 也可以使用。

原始答案

转换器只会在通过 JSON.NET 对您的实体进行序列化和反序列化期间调用。它不影响从代码中获取或设置属性值,也不影响 LINQ 查询和 DB 操作。

这里是转换器的实现:

public class ArrayString : JsonConverter
{
    private readonly char _delimiter;

    // UPDATE -- added default constructor, so that 
    // JsonConverter attribute can be specified without the 
    // delimiter parameter, in which case semicolon will be used
    public ArrayString() : this(';')
    {
    }

    public ArrayString(char delimiter)
    {
        _delimiter = delimiter;
    }

    public override bool CanRead => true;
    public override bool CanWrite => true;

    public override bool CanConvert(Type objectType)
    {
        return true; 
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType != JsonToken.StartArray)
        {
            return null;
        }

        var stringValue = new StringBuilder();

        while (reader.Read() && reader.TokenType == JsonToken.String)
        {
            if (stringValue.Length > 0)
            {
                stringValue.Append(_delimiter);
            }
            stringValue.Append((string)reader.Value);
        }

        return stringValue.ToString();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stringValue = value?.ToString();

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

        var arrayValue = stringValue.Split(_delimiter);

        writer.WriteStartArray();

        foreach (var item in arrayValue)
        {
            writer.WriteValue(item);
        }

        writer.WriteEndArray();
    }
}

以下是如何指定分隔符(本例中为分号):

[JsonConverter(typeof(ArrayString), ';')]
public string ServiceCodes { get; set; }

【讨论】:

  • 非常感谢@felix-b!我只是在 www.newtonsoftjson.com 上浏览文档并摸不着头脑。你是最棒的!
  • *newtonsoft.com/json
  • 发布后,它不会将 JSON 数组映射到属性。我想我必须实现一个自定义映射器。那会是正确的方向吗?
  • 在我的测试中,我在 EF6 实体上执行了 JsonConvert.SerializeObject 和 JsonConvert.PopulateObject。让我知道您如何公开您的 API(ASP.NET MVC?OData?哪些版本?),我会尝试重现
  • 我正在使用 ASP.NET Web API 2。
猜你喜欢
  • 2011-04-04
  • 2013-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-13
  • 2021-06-15
  • 1970-01-01
相关资源
最近更新 更多