我有一个枚举:
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
声明上,而不是 GridFilter
的 Operator
属性上:
[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
}