JsonConverter和EntityData

时间:2017-09-22 18:50:16

标签: c# json entity-framework azure json.net

我使用Azure使用数据库优先EF方法。 Azure Web服务中的一个实体定义如下:

public class Company : EntityData
{
    public string CompanyName { get; set; }
}

它从EntityData继承Id属性。 Id属性的类型为string。

在客户端,我有以下实体:

class Company
{
    [JsonConverter(typeof(IntConverter))]
    public int Id { get; set; }

    public string CompanyName { get; set; }
}

如上所示,我需要将Id从字符串转换为int。

我创建了以下JSON转换器:

class IntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null)
            return 0;

        int num;
        if (Int32.TryParse(reader.Value.ToString(), out num))
            return num;
        else
            return 0;
    }

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

它工作正常,但因为这是我的第一个JSON转换器,我不确定我是否正确创建它。我看到了转换器的例子,他们使用的是existingValue而不是reader.Value。就我而言,existingValue始终为0。

上述实施是否正确?

1 个答案:

答案 0 :(得分:0)

您的代码基本正确。

existingValue是先前存在于父c#模型中的值。通过将其传递到转换器,Json.NET允许转换器在populating现有模型或只读集合时工作。例如,如果您有一个带转换器的预分配只读属性:

public class RootObject
{
    readonly ObservableCollection<SomeClass> _collection = new ObservableCollection<SomeClass>();

    [JsonConverter(typeof(ObservableCollectionConverter<SomeClass>>)]
    public ObservableCollection<SomeClass> { get { return _collection; } }
}

然后,ObservableCollectionConverter<SomeClass> _collection方法会传递预先分配的value.ToString()值,并且可以向其中添加项目。

话虽如此,但仍有一些改进:

  1. ReadJson()中,您拨打ToString()public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // Int32 implements the IConvertible interface which has a ToString() overload // that takes an IFormatProvider specification. Pass the invariant format to guarantee // identical serialization in all cultures. var convertible = (IConvertible)value; serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo)); } 有可能返回特定于文化的字符串,例如可能会为WriteJson()插入小数点。相反,您应该按照NumberGroupSeparator序列化,如下所示:

    ReadJson()
  2. 需要在 int num; if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num)) return num; else return 0;

    中进行类似的修复
    ReadJson()
  3. 您的{"unexpectedProperty": "unexpectedValue"}无法抵御意外数据。例如,如果传入的JSON实际上具有数组或对象值(例如JsonReader),则public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { switch (reader.TokenType) { case JsonToken.Null: return null; case JsonToken.Integer: // Input was already an integer. Return it return (int)JToken.Load(reader); case JsonToken.String: { int num; if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num)) return num; else return 0; } default: throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path)); } 将无法正确地前进到输入的末尾。您应该检查invariant format并正确处理错误数据,例如:

            default:
                Debug.WriteLine(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
                reader.Skip();
                return 0;
    

    或者,如果您希望在不抛出异常的情况下使用和丢弃意外数据(我不建议这样做),您可以使用reader.TokenType

    true
  4. 通过属性应用转换器时,不会调用
  5. JsonReader.Skip()。但是,如果您将转换器添加到JsonConverter.CanConvert,那么从CanConvert返回NotImplementedException将会出现问题。相反,我建议抛出public override bool CanConvert(Type objectType) { return objectType == typeof(int) || objectType == typeof(int?); } 或正确实施该方法:

    class IntConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(int) || objectType == typeof(int?);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType,
            object existingValue, JsonSerializer serializer)
        {
            switch (reader.TokenType)
            {
                case JsonToken.Null:
                    return null;
    
                case JsonToken.Integer:
                    // Input was already an integer.  Return it
                    return (int)JToken.Load(reader);
    
                case JsonToken.String:
                    {
                        int num;
                        if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
                            return num;
                        else
                            return 0;
                    }
    
                default:
                    throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
            }
        }
    
        public override void WriteJson(JsonWriter writer, object value,
            JsonSerializer serializer)
        {
            // Int32 implements the IConvertible interface which has a ToString() overload
            // that takes an IFormatProvider specification.  Pass the invariant format to guarantee
            // identical serialization in all cultures.
            var convertible = (IConvertible)value;
            serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
        }
    }
    
  6. 因此,您的最终转换器可能如下所示:

    {{1}}

    样本JsonSerializerSettings.Converters显示最终转换器的严格和容忍版本。