ASP.NET MVC验证返回小写属性名称

时间:2018-12-19 16:49:14

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

在我的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的验证消息中返回小写字母的属性以反映命名策略?

2 个答案:

答案 0 :(得分:0)

解决方案是禁用自动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);
}

答案 1 :(得分:0)

有一个更简单的解决方案。使用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);
    }
}