Garantir que as chaves json sejam minúsculas no .NET

103

Existe uma maneira simples de usar JSON no .NET para garantir que as chaves sejam enviadas em minúsculas?

No momento estou usando a biblioteca Json.NET da newtonsoft e simplesmente usando

string loginRequest = JsonConvert.SerializeObject(auth);

Neste caso authé apenas o seguinte objeto

public class Authority
{
    public string Username { get; set; }
    public string ApiToken { get; set; }
}

Isto resulta em

{"Username":"Mark","ApiToken":"xyzABC1234"}

Existe uma maneira de garantir que as chaves usernamee apitokensejam exibidas em minúsculas?

Não quero simplesmente repassá-lo, é String.ToLower()claro, porque os valores para usernamee apitokensão maiúsculas e minúsculas.

Sei que posso fazer isso programaticamente e criar a string JSON manualmente, mas preciso disso para aproximadamente 20 strings de dados JSON e estou vendo se consigo economizar algum tempo. Estou me perguntando se há alguma biblioteca já construída que permite que você aplique minúsculas para a criação de chaves.

Marca
fonte
Talvez a biblioteca de serialização json ofereça algum tipo de atributos de serialização que você possa usar para alterar os nomes serializados json de suas propriedades.
tdammers
@tdammers, obrigado. Estou tentando encontrar algo que faça isso, mas até agora sem sucesso. Esperando que alguém aqui pudesse me indicar isso.
Marque em
1
Isso pode ser útil caso sua propriedade consista em uma palavra.
Lipotam
Hã. Estou tendo o problema oposto ... também - é engraçado você mencionar que "Nome de usuário" é uma mistura de letras maiúsculas e minúsculas. Você quis dizer "UserName"?
BrainSlugs83
Não, simplesmente que os valores precisavam permanecer mistos, caso as teclas Somente fossem o que eu precisava tocar. Valor deixe sozinho.
Marcar

Respostas:

176

Você pode criar um resolvedor de contratos personalizado para isso. O seguinte resolvedor de contratos converterá todas as chaves em minúsculas:

public class LowercaseContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        return propertyName.ToLower();
    }
}

Uso:

var settings = new JsonSerializerSettings();
settings.ContractResolver = new LowercaseContractResolver();
var json = JsonConvert.SerializeObject(authority, Formatting.Indented, settings);

Resultará em:

{"username":"Mark","apitoken":"xyzABC1234"}

Se você sempre deseja serializar usando o LowercaseContractResolver, considere envolvê-lo em uma classe para evitar a repetição:

public class LowercaseJsonSerializer
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new LowercaseContractResolver()
    };

    public static string SerializeObject(object o)
    {
        return JsonConvert.SerializeObject(o, Formatting.Indented, Settings);
    }

    public class LowercaseContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return propertyName.ToLower();
        }
    }
}

Que pode ser usado assim:

var json = LowercaseJsonSerializer.SerializeObject(new { Foo = "bar" });
// { "foo": "bar" }

ASP.NET MVC4 / WebAPI

Se você estiver usando ASP.NET MVC4 / WebAPI, você pode usar uma CamelCasePropertyNamesContractResolverbiblioteca de Newtonsoft.Json incluída por padrão.

alexn
fonte
alguma maneira razoável de fazer isso ao contrário? Para desserialização?
Shaun Rowan
1
@Anzeo Eu mesmo não tentei fazer isso e não encontrei nenhuma informação sobre isso na documentação. Uma solução seria envolver JsonConvert.SerializeObject em sua própria classe. Veja minha atualização.
alexn de
3
Parece que este contractresolver personalizado não leva em consideração o atributo JsonProperty, se você quiser especificar exceções ... por exemplo, [JsonProperty ("alternateName")] ainda fica em minúsculas ou há outra maneira de fazer isso?
rekna
2
1 para apontar o CamelCasePropertyNamesContractResolver. Agora descobri que System.Net.Http.Formatting.JsonContractResolveré o padrão na WebAPI e essa classe é interna. Acabo reescrevendo JsonContractResolvercom caixa de camelo. Alguém relatou que isso é público aspnetwebstack.codeplex.com/workitem/228
CallMeLaNN
10
CamelCasePropertyNamesContratResolvernão transforme as propriedades em minúsculas, apenas o primeiro caractere.
ToXinE
23
protected void Application_Start() {
    JsonConfig.Configure();   
}

public static class JsonConfig
{
    public static void Configure(){
        var formatters = GlobalConfiguration.Configuration.Formatters;
        var jsonFormatter = formatters.JsonFormatter;
        var settings = jsonFormatter.SerializerSettings;

        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}
Sagi
fonte
10

No Json.NET 9.0.1 e posterior, é possível garantir que todos os nomes de propriedades sejam convertidos em minúsculas usando um personalizado NamingStrategy. Esta classe extrai a lógica para o remapeamento algorítmico de nomes de propriedades do resolvedor de contratos para um objeto leve e separado que pode ser definido emDefaultContractResolver.NamingStrategy . Isso evita a necessidade de criar um customizadoContractResolver e, portanto, pode ser mais fácil de integrar em estruturas que já têm seus próprios resolvedores de contrato.

Defina LowercaseNamingStrategyo seguinte:

public class LowercaseNamingStrategy : NamingStrategy
{
    protected override string ResolvePropertyName(string name)
    {
        return name.ToLowerInvariant();
    }
}

Em seguida, serialize da seguinte maneira:

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver { NamingStrategy = new LowercaseNamingStrategy() },
};
string loginRequest = JsonConvert.SerializeObject(auth, settings);

Notas -

dbc
fonte
8

você pode usar "JsonProperty":

Uso:

public class Authority
{
    [JsonProperty("userName")] // or [JsonProperty("username")]
    public string Username { get; set; }
    [JsonProperty("apiToken")] // or [JsonProperty("apitoken")]
    public string ApiToken { get; set; }
}

var json  = JsonConvert.SerializeObject(authority);
Jorgelig
fonte
0

Para mim, usei uma combinação de algumas das outras respostas e terminei com esta

        return JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        });

estava mais perto de uma solução para o que eu procurava, pois não procurava criar o meu próprio

workabyte
fonte