Asp.net-Web-Api

列舉值不解析時如何將列舉作為字元串綁定失敗處理

  • May 12, 2022

在我們的 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());
   });
}

引用自:https://stackoverflow.com/questions/50365711