Json.NET StringEnumConverter并不总是工作



我有一个枚举:

public enum FilterOperator
    {
        [EnumMember(Value = "eq")]
        Equals,
        [EnumMember(Value = "gt")]
        GreaterThan,
        [EnumMember(Value = "lt")]
        LessThan,
        [EnumMember(Value = "in")]
        In,
        [EnumMember(Value = "like")]
        Like
    }

以及包含枚举属性的类:

public class GridFilter
{
    [JsonProperty("operator")]
    [JsonConverter(typeof(StringEnumConverter))]
    public FilterOperator Operator { get; set; }
}

该对象通过 WebAPI 操作传入,并按预期对"like"和"in"进行反序列化,但对"lg"或"gt"则不然。知道为什么吗?

更新:"喜欢"和"在"工作的原因是它们与枚举名称匹配。将大于重命名为 gt(等)有效。所以真正的问题是为什么不使用StringEnumConverter?

好吧,如果您希望在类GridFilter上下文之外反序列化时使用 [JsonConverter(typeof(StringEnumConverter))] 属性,则必须将 属性直接放在 enum 声明上,而不是 GridFilterOperator 属性上:

[JsonConverter(typeof(StringEnumConverter))] // Add this
public enum FilterOperator
{
    [EnumMember(Value = "eq")]
    Equals,
    [EnumMember(Value = "gt")]
    GreaterThan,
    [EnumMember(Value = "lt")]
    LessThan,
    [EnumMember(Value = "in")]
    In,
    [EnumMember(Value = "like")]
    Like
}
public class GridFilter
{
    [JsonProperty("operator")]
    //[JsonConverter(typeof(StringEnumConverter")] // Remove this
    public FilterOperator Operator { get; set; }
}

感谢大家的帮助!我意识到我做了什么。可悲的是,这很愚蠢,我提前为跑来跑去道歉。

由于我使用的是 GET,因此我将参数作为 url 查询参数发送,因此 WebAPI 使用普通的模型绑定器来映射名称而不是 JSON.NET。我实际上并没有发送 JSON,所以这完全有意义。这个问题帮助我意识到了这一点:复杂类型在 ApiController 参数中变为空

我的选择是创建一个自定义模型绑定器来正确处理枚举,或者更改为 POST 并使用 JSON.stringify() 发送数据。

这只是一个猜测,我还没有测试过。

我查看了EnumMemberAttribute的文档,它说:

要使用 EnumMemberAttribute ,创建一个枚举并将 DataContractAttribute 属性应用于枚举。然后将 EnumMemberAttribute 属性应用于需要位于序列化流中的每个成员。

当然,这是为了DataContractSerializer,但我想也许 JSON.net 考虑到同样的规则?

我会尝试将[DataContract]应用于enum.

[DataContract]
public enum FilterOperator
{
    [EnumMember(Value = "eq")]
    Equals,
    [EnumMember(Value = "gt")]
    GreaterThan,
    [EnumMember(Value = "lt")]
    LessThan,
    [EnumMember(Value = "in")]
    In,
    [EnumMember(Value = "like")]
    Like
}

这似乎是武断的,也是多余的。我知道 JSON.net 通常不依赖于这种东西,但也许在这种情况下它会?

我还注意到,如果存在元素,DataContractSerializer似乎会忽略元素而不[EnumMember] [DataContract],因此为了向后兼容,可能必须这样做。同样,不是超级合乎逻辑的。但这就是我所拥有的一切。

<小时 />

编辑:以真正的开发人员方式,我不只是测试这个,而是进入源代码。读取EnumMemberAttribute的部分可以在第 55 行找到,它这样做:

n2 = f.GetCustomAttributes(typeof(EnumMemberAttribute), true) 
      .Cast<EnumMemberAttribute>() 
      .Select(a => a.Value) 
      .SingleOrDefault() ?? f.Name; 

这让我觉得你所拥有的应该有效。

<小时 />

编辑 2:

好吧,这很奇怪。我只是自己尝试过,发现它有效。

public enum FilterOperator
{
    [EnumMember(Value = "eq")]
    Equals,
    [EnumMember(Value = "gt")]
    GreaterThan,
    [EnumMember(Value = "lt")]
    LessThan,
    [EnumMember(Value = "in")]
    In,
    [EnumMember(Value = "like")]
    Like
}
public class GridFilter
{
    [JsonProperty("operator")]
    [JsonConverter(typeof(StringEnumConverter))]
    public FilterOperator Operator { get; set; }
}

[TestMethod]
public void enumTest()
{
    GridFilter gf = new GridFilter()
    {
        Operator = FilterOperator.GreaterThan
    };
    var json = JsonConvert.SerializeObject(gf);
    // json yields {"operator":"gt"}
    var ret = JsonConvert.DeserializeObject<GridFilter>(json);
    // ret.Operator yields FilterOperator.GreaterThan
}

相关内容

  • 没有找到相关文章

最新更新