【问题标题】:ASP.NET MVC validation return lowercase property nameASP.NET MVC 验证返回小写的属性名称
【发布时间】:2020-09-22 20:17:29
【问题描述】:

在我的 ASP.NET MVC Core Web 应用程序中,属性的 Json 序列化设置为驼峰式(首字母小写):

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
    .AddJsonOptions(opt =>
    {
        opt.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
        opt.SerializerSettings.Converters.Add(new StringEnumConverter(true));
    });

客户端的序列化按预期工作。

但是当javascript客户端尝试发布数据并且该数据无效时,他会收到一条带有大写字母属性的验证消息,该验证消息是ModelState

{"Info":["The Info field is required."]}

有没有办法让 ASP.NET 在ModelState 的验证消息中返回小写属性以反映命名策略?

【问题讨论】:

    标签: asp.net-core-mvc asp.net-core-webapi


    【解决方案1】:

    解决方案是禁用自动 api 验证过滤器并使用验证消息创建自己的 json 结果:

    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true; 
    });
    

    在控制器中:

    protected ActionResult ValidationFailed()
    {
        var errorList = ModelState.ToDictionary(
            kvp => kvp.Key.ToCamelCase(),
            kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
        );
    
        return BadRequest(errorList);
    }
    
    public async Task<ActionResult> Create([FromBody]TCreateDto model)
    {
        if (ModelState.IsValid == false)
        {
            return ValidationFailed();
        }
    
        ...
    }
    

    字符串辅助方法:

    public static string ToCamelCase(this string name)
    {
        if (string.IsNullOrEmpty(name))
        {
            return name;
        }
        return name.Substring(0, 1).ToLower() + name.Substring(1);
    }
    

    【讨论】:

      【解决方案2】:

      有一个更简单的解决方案。使用 Fluent Validator 的ValidatorOptions.Global.PropertyNameResolver。取自 here 并转换为 C# 8 和 Fluent Validation 9:

      在 Startup.cs 中,ConfigureServices 使用:

      services
          .AddControllers()
          .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
          .AddFluentValidation(fv =>
          {
              fv.RegisterValidatorsFromAssemblyContaining<MyValidator>();
              // Convert property names to camelCase as Asp.Net Core does https://github.com/FluentValidation/FluentValidation/issues/226 
              ValidatorOptions.Global.PropertyNameResolver = CamelCasePropertyNameResolver.ResolvePropertyName;
          })
          .AddNewtonsoftJson(NewtonsoftUtils.SetupNewtonsoftOptionsDefaults);
      

      和解析器本身:

      /// <summary>
      /// Convert property names to camelCase as Asp.Net Core does 
      /// https://github.com/FluentValidation/FluentValidation/issues/226
      /// </summary>
      public class CamelCasePropertyNameResolver
      {
      
          public static string? ResolvePropertyName(Type type, MemberInfo memberInfo, LambdaExpression expression)
          {
              return ToCamelCase(DefaultPropertyNameResolver(type, memberInfo, expression));
          }
      
          private static string? DefaultPropertyNameResolver(Type type, MemberInfo memberInfo, LambdaExpression expression)
          {
              if (expression != null)
              {
                  var chain = PropertyChain.FromExpression(expression);
                  if (chain.Count > 0)
                  {
                      return chain.ToString();
                  }
              }
      
              if (memberInfo != null)
              {
                  return memberInfo.Name;
              }
      
              return null;
          }
      
          private static string? ToCamelCase(string? s)
          {
              if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0]))
              {
                  return s;
              }
      
              var chars = s.ToCharArray();
      
              for (var i = 0; i < chars.Length; i++)
              {
                  if (i == 1 && !char.IsUpper(chars[i]))
                  {
                      break;
                  }
      
                  var hasNext = (i + 1 < chars.Length);
                  if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
                  {
                      break;
                  }
      
                  chars[i] = char.ToLower(chars[i], CultureInfo.InvariantCulture);
              }
      
              return new string(chars);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-21
        • 2011-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多