How to make JSON output key with Pascal Case for a single action method?

323 Views Asked by At

I am trying to make JSON output returned from a single controller action (don't want to set it global) as like this (PascalCase) :

{
    "AuthenticationResult": {
        "AccessToken": "",
        "ExpiresIn": 0,
        "TokenType": "",
        "RefreshToken": "",
        "IdToken": ""
    }
}

DTO Class:

public class AuthResponse
{
    public AuthenticationResult authenticationResult { get; set; }
}

public class AuthenticationResult
{
    [JsonProperty("AccessToken")]
    public string AccessToken { get; set; }
    public int ExpiresIn { get; set; }
    public string TokenType { get; set; }
    public string RefreshToken { get; set; }
    public string IdToken { get; set; }
}

Controller Method:

public async Task<IHttpActionResult> GetAuthenticationToken(string Guid = null)
{
    try
    {
        var AuthResponse = await _Business.GetAuthenticationTokenAsync(Guid, null);

        return Ok(AuthResponse, this);
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

The DTOs AuthResponse and AuthenticationResult are not used elsewhere.

1

There are 1 best solutions below

0
dbc On BEST ANSWER

Modify your DTOs to add [JsonObject(NamingStrategyType = typeof(DefaultNamingStrategy))]:

[JsonObject(NamingStrategyType = typeof(DefaultNamingStrategy))]
public class AuthResponse
{
    [JsonProperty("AuthenticationResult")]
    public AuthenticationResult authenticationResult { get; set; }
}

[JsonObject(NamingStrategyType = typeof(DefaultNamingStrategy))]
public class AuthenticationResult
{
    [JsonProperty("AccessToken")]
    public string AccessToken { get; set; }
    public int ExpiresIn { get; set; }
    public string TokenType { get; set; }
    public string RefreshToken { get; set; }
    public string IdToken { get; set; }
}

You need to do this because, if you are using CamelCasePropertyNamesContractResolver, it will even camel-case property names specified via JsonPropertyAttribute.PropertyName. Applying a naming strategy to the object itself prevents this behavior.

Demo fiddle #1 here.

Alternatively, you could modify your global settings and use a contract resolver that does not override specified names by setting NamingStrategy.OverrideSpecifiedNames = false: [1]

var settings = new JsonSerializerSettings();
settings.ContractResolver = new DefaultContractResolver { 
    NamingStrategy = new CamelCaseNamingStrategy { 
        OverrideSpecifiedNames = false // Prevent modification of property names set by [JsonProperty("name")]
    } 
};

And then your [JsonProperty("AuthenticationResult")] will not get camel-cased. However, since you only want to pascal-case a single action method, this is probably not the preferred solution.

Demo fiddle #2 here.


[1] Do not modify the naming strategy of CamelCasePropertyNamesContractResolver, create an instance of DefaultContractResolver instead. CamelCasePropertyNamesContractResolver shares contracts across all instances of its type, so modifying one instance will change its behavior across your application. For details see e.g. this answer to Json.Net: Html Helper Method not regenerating.