列舉值不解析時如何將列舉作為字元串綁定失敗處理
在我們的 ASP.net Core Web API 應用程序中,當我的控制器方法接受具有 ENUM 屬性的複雜對象時,我正在尋找一種方法來擷取綁定錯誤,而 ENUM 被反序列化為字元串。
例如。
class Person { public string Name {get; set;} public SexEnum Sex {get; set;} } enum SexEnum { Male, Female, Other }我們使用系統範圍
StringEnumConverter的 JSON 序列化實例Person如下所示:{ "name": "Ann", "sex": "female" }現在,如果我發布此 JSON(請注意
sex屬性中的錯字):{ "name": "Ann", "sex": "femal" }由於綁定失敗,控制器方法接收到的整個對象為 NULL。
我想捕捉那個綁定錯誤,而不是讓管道進入控制器,好像沒有任何問題,而是向客戶端返回一個 BAD REQUEST,包括哪個屬性值無法綁定的詳細資訊。
我知道我要反序列化的類型,我知道我要反序列化的屬性類型,並且我可以看到該值沒有解析為類型。所以我認為必須有一種方法可以向客戶提供這些細節。我只是不知道在哪里以及如何插入。
我希望解決方案是系統範圍的,以便涵蓋所有列舉,而不必將屬性放在模型的屬性或列舉本身上。(這是因為我們將 API 模型作為 nuget 包分發,它不能有任何依賴項。)
跟進以上簡單 Ged 的回答,AFAICS,這實際上無法完成,因為模型綁定異常被吞沒(https://github.com/aspnet/Mvc/issues/3898)
ModelState包含模型綁定錯誤,您可以從中獲取一些資訊。由於我們目前僅使用 JSON 序列化,因此我最終實現了一個過濾器來ModelState檢查JsonSerializationException. 它並不完美,例如。要從中獲取請求的值(綁定失敗),JsonSerializationException您需要解析內部異常消息。如果有人找到更好的解決方案,我會很高興聽到。
我們最近遇到了這個問題,並編寫了自己的屬性來處理它:
public class ValidEnumValueAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { Type enumType = value.GetType(); bool valid = Enum.IsDefined(enumType, value); if(!valid) { return new ValidationResult($"{value} is not a valid value for type {enumType.Name}"); } return ValidationResult.Success; } } class Person { public string Name {get; set;} [ValidEnumValue] public SexEnum Sex {get; set;} }然後將錯誤添加到 ModelState 中,以便您可以
ModelState.IsValid用來檢查值是否有效。if(!ModelState.IsValid) { return BadRequest(ModelState); }編輯
如果您不想使用屬性,那麼您可以從 NewtonSoft 派生一個新的轉換器,
StringEnumConverter並在讀取 json 之前檢查該值是否有效,例如public class validEnumConverter : StringEnumConverter { public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if(!Enum.IsDefined(objectType, reader.Value)) { throw new ArgumentException("Invalid enum value"); } return base.ReadJson(reader, objectType, existingValue, serializer); } }這將添加到您的啟動類中的 JsonOptions 中:
public void ConfigureServices(IServiceCollection services) { services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.Converters.Add(new validEnumConverter()); }); }