1

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.

dbc
  • 104,963
  • 20
  • 228
  • 340
BlackCat
  • 1,932
  • 3
  • 19
  • 47
  • 1) What version of asp.net are you using? 2) `[JsonProperty("AccessToken")]` is from Json.NET not System.Text.Json, are you certain you are using Json.NET? 3) If using Json.NET, how are your `JsonSerializerSettings` configured? 4) Are your DTOs `AuthResponse` and `AuthenticationResult` used elsewhere, or can they be modifier to force a pascal case return? – dbc May 19 '23 at 17:15
  • .Net Framework 4.6.1 – BlackCat May 19 '23 at 17:17
  • Then definitely Json.NET. Can you modify your DTOs to add attributes? – dbc May 19 '23 at 17:18
  • and, AuthResponse/AuthenticationResult is not used elsewhere – BlackCat May 19 '23 at 17:19
  • Tried to modify using JsonProperty, but it doesn't work – BlackCat May 19 '23 at 17:20

1 Answers1

3

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.

dbc
  • 104,963
  • 20
  • 228
  • 340