After upgrading to .NET 8 Isolated worker from .NET 6 in-process, my API responses are all in camelCase. That is expected, but I cannot get any solution to work to return PascalCase instead.
I've tried countless solutions:
- Converting fully to
System.Text.Json
- Using a custom
JsonNamingPolicy
to convert toPascalCase
- Adding a
DefaultJsonTypeInfoResolver
to the options - Using
[JsonPropertyName]
which DOES work, but is not a viable solution due to there being thousands of properties in this project.
What is odd is the serializer seems to be working - JsonSerializer.Serialize(myData)
results in the correct PascalCase string. BUT when returning via an OkObjectResult(myData)
, the JSON is always camelCase.
Please help - here is my Program.cs
:
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
{
builder.Services.Configure<JsonSerializerOptions>(serializationOptions =>
{
serializationOptions.PropertyNamingPolicy = new PascalCaseJsonNamingPolicy();
serializationOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
serializationOptions.WriteIndented = true;
});
})
.ConfigureServices(services => FunctionStart.Configure(services))
.Build();
host.Run();
}
And my custom PascalCase
policy:
public class PascalCaseJsonNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
if (string.IsNullOrEmpty(name))
{
return name;
}
Span<char> chars = name.ToCharArray();
chars = FixCasing(chars);
return new string(chars);
}
private static Span<char> FixCasing(Span<char> chars)
{
if (chars.Length > 0 && char.IsLower(chars[0]))
{
chars[0] = char.ToUpper(chars[0]);
}
return chars;
}
}
Here is a sample object that I've been testing with:
public class Document
{
[JsonPropertyName("id")]
public string Id { get; set; }
public string UniqueId { get; set; }
public string UserId { get; set; }
}
After upgrading to .NET 8 Isolated worker from .NET 6 in-process, my API responses are all in camelCase. That is expected, but I cannot get any solution to work to return PascalCase instead.
I've tried countless solutions:
- Converting fully to
System.Text.Json
- Using a custom
JsonNamingPolicy
to convert toPascalCase
- Adding a
DefaultJsonTypeInfoResolver
to the options - Using
[JsonPropertyName]
which DOES work, but is not a viable solution due to there being thousands of properties in this project.
What is odd is the serializer seems to be working - JsonSerializer.Serialize(myData)
results in the correct PascalCase string. BUT when returning via an OkObjectResult(myData)
, the JSON is always camelCase.
Please help - here is my Program.cs
:
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
{
builder.Services.Configure<JsonSerializerOptions>(serializationOptions =>
{
serializationOptions.PropertyNamingPolicy = new PascalCaseJsonNamingPolicy();
serializationOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
serializationOptions.WriteIndented = true;
});
})
.ConfigureServices(services => FunctionStart.Configure(services))
.Build();
host.Run();
}
And my custom PascalCase
policy:
public class PascalCaseJsonNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
if (string.IsNullOrEmpty(name))
{
return name;
}
Span<char> chars = name.ToCharArray();
chars = FixCasing(chars);
return new string(chars);
}
private static Span<char> FixCasing(Span<char> chars)
{
if (chars.Length > 0 && char.IsLower(chars[0]))
{
chars[0] = char.ToUpper(chars[0]);
}
return chars;
}
}
Here is a sample object that I've been testing with:
public class Document
{
[JsonPropertyName("id")]
public string Id { get; set; }
public string UniqueId { get; set; }
public string UserId { get; set; }
}
Share
Improve this question
edited Jan 29 at 17:48
marc_s
757k184 gold badges1.4k silver badges1.5k bronze badges
asked Jan 29 at 14:12
Brandon GrotheBrandon Grothe
911 silver badge7 bronze badges
11
|
Show 6 more comments
3 Answers
Reset to default 3FINALLY I found the issue. Per Microsoft docs
ASP.NET Core has its own serialization layer, and it is not affected by customizing general serialization configuration. To customize the serialization behavior used for your HTTP triggers, you need to include an .AddMvc() call as part of service registration. The returned IMvcBuilder can be used to modify ASP.NET Core's JSON serialization settings.
Thus, leveraging the following code allowed the AspNetCore calls like OkObjectResult() to serialize to PascalCase:
var mvcBuilder = builder.Services.AddMvc().AddNewtonsoftJson();
mvcBuilder.Services.Configure<MvcNewtonsoftJsonOptions>(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
This isn't a System.Text.Json issue. JsonObjectSerializer
is part of the Azure SDK. Looking at the JsonObjectSerializer.cs code on GitHub, I see that JsonPropertyName
overrides the naming policy. If that attribute exists, the class will return the Name
as-is, without applying the policy
private string GetPropertyName(MemberInfo memberInfo)
{
// Mimics property name determination based on
// https://github/dotnet/runtime/blob/dc8b6f90/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs#L53-L90
JsonPropertyNameAttribute? nameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(false);
if (nameAttribute != null)
{
return nameAttribute.Name
?? throw new InvalidOperationException($"The JSON property name for '{memberInfo.DeclaringType}.{memberInfo.Name}' cannot be null.");
}
else if (_options.PropertyNamingPolicy != null)
{
return _options.PropertyNamingPolicy.ConvertName(memberInfo.Name)
?? throw new InvalidOperationException($"The JSON property name for '{memberInfo.DeclaringType}.{memberInfo.Name}' cannot be null.");
}
else
{
return memberInfo.Name;
}
}
If you want to avoid this you should rename Chunks
to Documents
and remove JsonPropertyName
I am able to send response in pascal case using below code:
Function.cs:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using System.Text.Json;
namespace RithApp1
{
public class Function1
{
private readonly ILogger<Function1> ri_lg;
public Function1(ILogger<Function1> rilg)
{
ri_lg = rilg;
}
[Function("Function1")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
{
ri_lg.LogInformation("Hello Rithwik, Function execeution started");
var test = new
{
Id = 8,
UserName = "Rithwik Bojja",
Email = "[email protected]"
};
string ri_out = JsonSerializer.Serialize(test);
return new OkObjectResult(ri_out);
}
}
}
Program.cs:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Text.Json;
public class Program
{
public static void Main()
{
var cho = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(rith =>
{
rith
.AddHttpClient()
.Configure<JsonSerializerOptions>(options =>
{
options.PropertyNamingPolicy = null;
options.PropertyNameCaseInsensitive = true;
});
})
.Build();
cho.Run();
}
}
Output:
myData
that reproduces the problem. Thanks! – dbc Commented Jan 29 at 14:23JsonObjectSerializer
inAzure.Core.Serialization
andWorkerOptions
inMicrosoft.Azure.Functions.Worker
so are you writing an Azure worker? A client? Please tag your question to clarify. Thanks! – dbc Commented Jan 29 at 14:34