Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to camelCase property names #226

Closed
aschaible opened this issue Mar 4, 2016 · 5 comments
Closed

Add option to camelCase property names #226

aschaible opened this issue Mar 4, 2016 · 5 comments

Comments

@aschaible
Copy link

Due to the conventions mismatch of .NET and javascript, lots of JSON serializers provide the ability to serialize outbound property names in models in a camelCase format. It's great that FluentValidation gives us the ability to change the property name, but it would be even better if we had a way to extend the way property names are generated, and include a few common formats.

If you could point me in the right direction, I could submit a PR for this.

@JeremySkinner
Copy link
Member

Hi Adam

You can actually already do this. FV has support for both Propertname resolvers and displayname resolvers which allow you to customise how the property names are generated. These are accessible on the global static ValidatorOptions class.

@aschaible
Copy link
Author

Thanks @JeremySkinner - I was able to get this working as you described with the PropertyNameResolver. Would you be interested in a PR that introduces an IDisplayNameResolver and IPropertyNameResolver interfaces and your default implementation, as well as a camel case version?

@JeremySkinner
Copy link
Member

I'm not really keen to introduce such a large breaking change like that, so I'd rather stick with the existing delegate-based approach rather than introducing a new interface. Perhaps you'd like to include the code you wrote here though? I can then put it in the wiki as an example of how to write a custom resolver.

Thanks!

@aschaible
Copy link
Author

aschaible commented Mar 17, 2016

Sure thing!

Here is my camel case property resolver. This was taken directly from the json.net code:

 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);
    }
}

And then in startup.cs:

ValidatorOptions.PropertyNameResolver = CamelCasePropertyNameResolver.ResolvePropertyName;

@rusticpow
Copy link

rusticpow commented Apr 16, 2018

Snake case if someone want:

internal class SnakeCasePropertyResolver
{
        
        public static string ResolvePropertyName(Type type, MemberInfo memberInfo, LambdaExpression expression)
        {
            return ToSnakeCase(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;
        }

        public string GetSerializedName(string propertyName)
        {
            return ToSnakeCase(propertyName);
        }
 
        public static string ToSnakeCase(string propertyName)
        {
            var parts       = new List<string>();
            var currentWord = new StringBuilder();
 
            foreach (var c in propertyName)
            {
                if (char.IsUpper(c) && currentWord.Length > 0)
                {
                    parts.Add(currentWord.ToString());
                    currentWord.Clear();
                }
                currentWord.Append(char.ToLower(c));
            }
 
            if (currentWord.Length > 0)
            {
                parts.Add(currentWord.ToString());
            }
 
            return string.Join("_", parts.ToArray());
        }
    }

@lock lock bot locked and limited conversation to collaborators Aug 20, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants