Skip to content

Commit 29ca564

Browse files
Serialize enum as string: retarget net10.0, ConfigureHttpJsonOptions, DataContractJsonSerializer and source-generation samples
Retarget all seven projects from net6.0 to net10.0 and refresh packages against NuGet: Newtonsoft.Json 13.0.4, Microsoft.AspNetCore.Mvc.NewtonsoftJson 10.0.11, Microsoft.AspNetCore.Mvc.Testing 10.0.11, Microsoft.NET.Test.Sdk 18.9.0, xunit 2.9.3, xunit.runner.visualstudio 3.1.5 (the v2-compatible line), coverlet.collector 10.0.1. The System.Text.Json package references are dropped because the library is in-box on net10.0. Minimal API sample now uses ConfigureHttpJsonOptions instead of Configure<JsonOptions>; both are the same Microsoft.AspNetCore.Http.Json.JsonOptions object, and the extension is the first-class way to reach it. Dead app.UseAuthorization() removed from both Web API samples: neither registers authentication or authorization. New coverage: - JsonStringEnumMemberName, both with a registered JsonStringEnumConverter (custom string) and without one (still a number). - DataContractJsonSerializer: enums are always written as numbers, EnumMember is ignored, reading the string form back throws, an undefined number is accepted, and the XML DataContractSerializer does honour EnumMember on the same type. - Source-generated serialization through a JsonSerializerContext with UseStringEnumConverter set. Build clean with 0 warnings, 27 tests passing on SDK 10.0.302.
1 parent a59a6f6 commit 29ca564

16 files changed

Lines changed: 355 additions & 204 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
2-
3-
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
5-
<ImplicitUsings>enable</ImplicitUsings>
6-
<Nullable>enable</Nullable>
7-
</PropertyGroup>
8-
9-
</Project>
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
</Project>
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
2-
3-
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
5-
<Nullable>enable</Nullable>
6-
<ImplicitUsings>enable</ImplicitUsings>
7-
</PropertyGroup>
8-
9-
<ItemGroup>
10-
<PackageReference Include="System.Text.Json" Version="6.0.2" />
11-
</ItemGroup>
12-
<ItemGroup>
13-
<InternalsVisibleTo Include="JsonSerialization.Native.EnumAsString.MinimalApiTests" />
14-
</ItemGroup>
15-
<ItemGroup>
16-
<ProjectReference Include="..\JsonSerialization.EnumAsString.Models\JsonSerialization.EnumAsString.Models.csproj" />
17-
</ItemGroup>
18-
19-
</Project>
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<InternalsVisibleTo Include="JsonSerialization.Native.EnumAsString.MinimalApiTests" />
11+
</ItemGroup>
12+
<ItemGroup>
13+
<ProjectReference Include="..\JsonSerialization.EnumAsString.Models\JsonSerialization.EnumAsString.Models.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
using JsonSerialization.EnumAsString.Models;
2-
using Microsoft.AspNetCore.Http.Json;
3-
using System.Text.Json.Serialization;
4-
5-
var builder = WebApplication.CreateBuilder(args);
6-
builder.Services.Configure<JsonOptions>(options =>
7-
{
8-
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
9-
});
10-
11-
var app = builder.Build();
12-
13-
app.MapGet("/poster", () => Canvas.Poster);
14-
app.MapGet("/schedule", () => new { Description = "Exhibition", Day = DayOfWeek.Monday });
15-
1+
using JsonSerialization.EnumAsString.Models;
2+
using System.Text.Json.Serialization;
3+
4+
var builder = WebApplication.CreateBuilder(args);
5+
builder.Services.ConfigureHttpJsonOptions(options =>
6+
{
7+
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
8+
});
9+
10+
var app = builder.Build();
11+
12+
app.MapGet("/poster", () => Canvas.Poster);
13+
app.MapGet("/schedule", () => new { Description = "Exhibition", Day = DayOfWeek.Monday });
14+
1615
app.Run();
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<IsPackable>false</IsPackable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" />
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
12-
<PackageReference Include="System.Text.Json" Version="6.0.2" />
13-
<PackageReference Include="xunit" Version="2.4.1" />
14-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
10+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.11" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
12+
<PackageReference Include="xunit" Version="2.9.3" />
13+
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
1514
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1615
<PrivateAssets>all</PrivateAssets>
1716
</PackageReference>
18-
<PackageReference Include="coverlet.collector" Version="3.1.0">
17+
<PackageReference Include="coverlet.collector" Version="10.0.1">
1918
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2019
<PrivateAssets>all</PrivateAssets>
2120
</PackageReference>
2221
</ItemGroup>
2322

24-
<ItemGroup>
25-
<ProjectReference Include="..\JsonSerialization.Native.EnumAsString.MinimalApi\JsonSerialization.Native.EnumAsString.MinimalApi.csproj" />
23+
<ItemGroup>
24+
<ProjectReference Include="..\JsonSerialization.Native.EnumAsString.MinimalApi\JsonSerialization.Native.EnumAsString.MinimalApi.csproj" />
2625
</ItemGroup>
2726

2827
</Project>
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
2-
3-
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
5-
<Nullable>enable</Nullable>
6-
<ImplicitUsings>enable</ImplicitUsings>
7-
</PropertyGroup>
8-
<ItemGroup>
9-
<InternalsVisibleTo Include="JsonSerialization.Native.EnumAsStringTests" />
10-
</ItemGroup>
11-
<ItemGroup>
12-
<PackageReference Include="System.Text.Json" Version="6.0.2" />
13-
</ItemGroup>
14-
<ItemGroup>
15-
<ProjectReference Include="..\JsonSerialization.EnumAsString.Models\JsonSerialization.EnumAsString.Models.csproj" />
16-
</ItemGroup>
17-
18-
</Project>
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<InternalsVisibleTo Include="JsonSerialization.Native.EnumAsStringTests" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<ProjectReference Include="..\JsonSerialization.EnumAsString.Models\JsonSerialization.EnumAsString.Models.csproj" />
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
using System.Text.Json.Serialization;
2-
3-
var builder = WebApplication.CreateBuilder(args);
4-
5-
builder.Services.AddControllers()
6-
.AddJsonOptions(options =>
7-
{
8-
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
9-
});
10-
11-
var app = builder.Build();
12-
13-
app.UseAuthorization();
14-
15-
app.MapControllers();
16-
1+
using System.Text.Json.Serialization;
2+
3+
var builder = WebApplication.CreateBuilder(args);
4+
5+
builder.Services.AddControllers()
6+
.AddJsonOptions(options =>
7+
{
8+
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
9+
});
10+
11+
var app = builder.Build();
12+
13+
app.MapControllers();
14+
1715
app.Run();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace JsonSerialization.Native.EnumAsStringTests.CustomNames;
2+
3+
public record struct ToggleControl(string Name, ToggleType Type);
4+
5+
public enum ToggleType
6+
{
7+
[JsonStringEnumMemberName("Enable/Disable")]
8+
EnableDisable,
9+
10+
[JsonStringEnumMemberName("Visible/Hidden")]
11+
VisibleHidden,
12+
13+
[JsonStringEnumMemberName("Editable/Readonly")]
14+
EditableReadonly,
15+
}
Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,68 @@
1-
using JsonSerialization.EnumAsString.Models;
2-
3-
namespace JsonSerialization.Native.EnumAsStringTests;
4-
5-
public class CustomSerializationUnitTest : UnitTestBase
6-
{
7-
[Fact]
8-
public void GivenEnum_WhenSerializeWithPropertyCamelCasePolicy_ThenDoesNotCamelCaseEnumValues()
9-
{
10-
var options = new JsonSerializerOptions
11-
{
12-
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
13-
};
14-
options.Converters.Add(new JsonStringEnumConverter());
15-
16-
var json = JsonSerializer.Serialize(Canvas.Poster, options);
17-
18-
Assert.Equal("{\"name\":\"Poster\",\"backColor\":\"LightGray\",\"medium\":\"Water\",\"pen\":{\"name\":\"Simple\",\"color\":\"Red\"}}", json);
19-
}
20-
21-
[Fact]
22-
public void GivenEnum_WhenSerializeWithEnumCamelCasePolicy_ThenCamelCaseEnumValues()
23-
{
24-
var options = new JsonSerializerOptions();
25-
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
26-
27-
var json = JsonSerializer.Serialize(Canvas.Poster, options);
28-
29-
Assert.Equal("{\"Name\":\"Poster\",\"BackColor\":\"lightGray\",\"Medium\":\"water\",\"Pen\":{\"Name\":\"Simple\",\"Color\":\"red\"}}", json);
30-
}
31-
32-
[Fact]
33-
public void GivenEnum_WhenDecoratedWithEnumMember_ThenIgnoresEnumMemberOnSerialize()
34-
{
35-
var controls = new ToggleControl[]
36-
{
37-
new("toggle1", ToggleType.EnableDisable),
38-
new("toggle2", ToggleType.VisibleHidden)
39-
};
40-
var json = SerializeWithStringEnum(controls);
41-
42-
Assert.Equal("[{\"Name\":\"toggle1\",\"Type\":\"EnableDisable\"},{\"Name\":\"toggle2\",\"Type\":\"VisibleHidden\"}]", json);
43-
}
44-
}
1+
using JsonSerialization.EnumAsString.Models;
2+
3+
namespace JsonSerialization.Native.EnumAsStringTests;
4+
5+
public class CustomSerializationUnitTest : UnitTestBase
6+
{
7+
[Fact]
8+
public void GivenEnum_WhenSerializeWithPropertyCamelCasePolicy_ThenDoesNotCamelCaseEnumValues()
9+
{
10+
var options = new JsonSerializerOptions
11+
{
12+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
13+
};
14+
options.Converters.Add(new JsonStringEnumConverter());
15+
16+
var json = JsonSerializer.Serialize(Canvas.Poster, options);
17+
18+
Assert.Equal("{\"name\":\"Poster\",\"backColor\":\"LightGray\",\"medium\":\"Water\",\"pen\":{\"name\":\"Simple\",\"color\":\"Red\"}}", json);
19+
}
20+
21+
[Fact]
22+
public void GivenEnum_WhenSerializeWithEnumCamelCasePolicy_ThenCamelCaseEnumValues()
23+
{
24+
var options = new JsonSerializerOptions();
25+
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
26+
27+
var json = JsonSerializer.Serialize(Canvas.Poster, options);
28+
29+
Assert.Equal("{\"Name\":\"Poster\",\"BackColor\":\"lightGray\",\"Medium\":\"water\",\"Pen\":{\"Name\":\"Simple\",\"Color\":\"red\"}}", json);
30+
}
31+
32+
[Fact]
33+
public void GivenEnum_WhenDecoratedWithEnumMember_ThenIgnoresEnumMemberOnSerialize()
34+
{
35+
var controls = new ToggleControl[]
36+
{
37+
new("toggle1", ToggleType.EnableDisable),
38+
new("toggle2", ToggleType.VisibleHidden)
39+
};
40+
var json = SerializeWithStringEnum(controls);
41+
42+
Assert.Equal("[{\"Name\":\"toggle1\",\"Type\":\"EnableDisable\"},{\"Name\":\"toggle2\",\"Type\":\"VisibleHidden\"}]", json);
43+
}
44+
45+
[Fact]
46+
public void GivenEnum_WhenDecoratedWithJsonStringEnumMemberName_ThenSerializeAsSpecifiedString()
47+
{
48+
var controls = new CustomNames.ToggleControl[]
49+
{
50+
new("toggle1", CustomNames.ToggleType.EnableDisable),
51+
new("toggle2", CustomNames.ToggleType.VisibleHidden)
52+
};
53+
54+
var json = SerializeWithStringEnum(controls);
55+
56+
Assert.Equal("[{\"Name\":\"toggle1\",\"Type\":\"Enable/Disable\"},{\"Name\":\"toggle2\",\"Type\":\"Visible/Hidden\"}]", json);
57+
}
58+
59+
[Fact]
60+
public void GivenEnum_WhenDecoratedWithJsonStringEnumMemberNameButNoConverterRegistered_ThenSerializeAsNumber()
61+
{
62+
var control = new CustomNames.ToggleControl("toggle1", CustomNames.ToggleType.EnableDisable);
63+
64+
var json = Serialize(control);
65+
66+
Assert.Equal("{\"Name\":\"toggle1\",\"Type\":0}", json);
67+
}
68+
}

0 commit comments

Comments
 (0)