Web API - 将编码的输入表单设置为复杂类型的枚举允许无效值



>我有一个具有许多属性的复杂类型,包括一个枚举。当将数据(application/x-www-form-urlencoded)PUTing到具有此类型作为参数的Web API方法时,它似乎允许为枚举属性的值传递任何字符串值。如果传递的值是枚举的成员之一,则它正确分配值,但如果传递了无效值,则它只是分配枚举的第一个成员。

描述问题的简单示例 - 给定模型类:

public enum EdibleFarmAnimal {
   Sheep = 0,
   Cow = 1,
   Chicken = 2
}
public class ExampleModel {
    public EdibleFarmAnimal EatThis { get; set; }
    public string AnotherIrrelevantProperty { get; set; }
}

。和 Web API 方法:

[HttpPut]
[ActionName("Put")]
public void Put(long id, ExampleModel model) {
    // Do something with the model
}

如果我将EatThis=Cow&AnotherIrrelevantProperty=cheese放入相关 URL,它会按预期和模型工作。EatThis等于EdibleFarmAnimal.Cow,但是如果我EatThis=Horse&AnotherIrrelevantProperty=cheese那么模型。EatThis 设置为 EdibleFarmAnimal.Sheep,而我希望(并期望)抛出某种错误,因为输入对于它被反序列化的类型无效。

C# 中的Enum的默认值为 0 ,因此当它无法解析您的输入时,它默认为 0,代表枚举中的Sheep(MSDN 文章)。

您可以做的是创建一个Invalid枚举元素并将其分配给0

public enum EdibleFarmAnimal {
   Invalid = 0,
   Sheep = 1,
   Cow = 2,
   Chicken = 3
}

然后检查您的输入是否有效。

多亏了 Vsevolod 的回答,我能够理解它为什么要分配它的值,但是检测场景的解决方案是检查 Web API 方法中的 ModelState.IsValid 属性 - 如果无法分析枚举值或日期时间,或者您添加到模型的任何特定验证属性未针对给定输入传递,则此属性设置为 false。如本文所述:

验证失败时,Web API 不会自动向客户端返回错误。由控制器操作来检查模型状态并做出适当的响应。

因此,要更正原始示例,使其现在引发适当的错误:

[HttpPut]
[ActionName("Put")]
public void Put(long id, ExampleModel model) {
    if (!ModelState.IsValid) throw new HttpResponseException(HttpStatusCode.BadRequest);
    // Do something with the model
}

此答案描述了一种通过使用自定义属性来应用此类验证的好方法,作为检查每个 API 调用的替代方法。