Skip to content

Add migrating-newtonsoft-to-system-text-json skill - #89

Closed
mrsharm wants to merge 5 commits into
dotnet:mainfrom
mrsharm:musharm/migrating-newtonsoft-to-stj-skill
Closed

Add migrating-newtonsoft-to-system-text-json skill#89
mrsharm wants to merge 5 commits into
dotnet:mainfrom
mrsharm:musharm/migrating-newtonsoft-to-stj-skill

Conversation

@mrsharm

@mrsharm mrsharm commented Feb 23, 2026

Copy link
Copy Markdown
Member

Summary

Adds the migrating-newtonsoft-to-system-text-json skill for migrating from Newtonsoft.Json (Json.NET) to System.Text.Json.

Skill Validation Results — migrating-newtonsoft-to-system-text-json

Skill Test Baseline With Skill Δ Verdict
migrating-newtonsoft-to-system-text-json Migrate model with Newtonsoft.Json attributes to System.Text.Json 4.0/5 4.3/5 +0.3

Overall improvement: +10.8% (3 runs, not statistically significant)

Model: claude-opus-4.6 | Judge: claude-opus-4.6

3 Iterations.

What the Skill Teaches

  • Complete attribute mapping table (JsonProperty -> JsonPropertyName, NullValueHandling -> JsonIgnoreCondition, etc.)
  • Behavioral differences that break silently (default casing, strict parsing, case sensitivity, numbers-in-strings)
  • Custom converter migration (Newtonsoft JsonConverter -> System.Text.Json JsonConverter with Utf8JsonReader/Writer)
  • JToken/JObject -> JsonDocument/JsonElement (read-only) or JsonNode (mutable DOM)
  • Polymorphic serialization with [JsonDerivedType] (.NET 7+)
  • JsonExtensionData Dictionary value type change (JToken -> JsonElement)

Why This Skill Passes

The model frequently misses subtle behavioral differences between the two serializers. It suggests System.Text.Json code that compiles but behaves differently at runtime (wrong casing, strict parsing failures, missing case insensitivity). This skill provides the comprehensive mapping.

Files

  • src/dotnet/skills/migrating-newtonsoft-to-system-text-json/SKILL.md
  • src/dotnet/tests/migrating-newtonsoft-to-system-text-json/eval.yaml

…vement)

Teaches migration from Newtonsoft.Json to System.Text.Json: attribute
mapping differences, behavioral changes (casing, strictness, null handling),
custom converter conversion, JToken->JsonElement/JsonNode migration, and
polymorphic serialization with JsonDerivedType.

Eval results: +13.8% improvement over baseline (threshold: 10%)
Includes eval.yaml with migration scenario + negative test.
Copilot AI review requested due to automatic review settings February 23, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new skill for migrating from Newtonsoft.Json to System.Text.Json. The skill aims to help developers understand behavioral differences, attribute mappings, and common migration patterns. The PR includes both the skill documentation (SKILL.md) and evaluation scenarios (eval.yaml) with a reported 13.8% improvement in evaluation metrics.

Changes:

  • Added migrating-newtonsoft-to-system-text-json skill with comprehensive migration guidance
  • Added evaluation scenarios testing attribute migration and skill activation patterns
  • Included behavioral differences table, attribute mappings, converter examples, and configuration guidance

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 11 comments.

File Description
src/dotnet/skills/migrating-newtonsoft-to-system-text-json/SKILL.md Comprehensive migration guide covering behavioral differences, attribute mappings, custom converters, and configuration examples
src/dotnet/tests/migrating-newtonsoft-to-system-text-json/eval.yaml Two evaluation scenarios: positive migration case and negative case to prevent false activation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/dotnet/skills/migrating-newtonsoft-to-system-text-json/SKILL.md Outdated
Comment thread src/dotnet/skills/migrating-newtonsoft-to-system-text-json/SKILL.md Outdated
{
// Match Newtonsoft.Json default behavior:
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; // Newtonsoft default
options.PropertyNameCaseInsensitive = true; // Newtonsoft default

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "Newtonsoft default" on line 68 is misleading. PropertyNameCaseInsensitive is not a Newtonsoft.Json default behavior. Newtonsoft.Json is case-sensitive by default during deserialization, just like System.Text.Json.

This comment should be removed or changed to clarify that this is an optional configuration, not matching a Newtonsoft default.

Copilot uses AI. Check for mistakes.
Comment thread src/dotnet/skills/migrating-newtonsoft-to-system-text-json/SKILL.md Outdated
- "Replaced NullValueHandling.Ignore with [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]"
- "Replaced [JsonConverter(typeof(StringEnumConverter))] with System.Text.Json equivalent (JsonStringEnumConverter)"
- "Changed [JsonExtensionData] Dictionary value type from JToken to JsonElement (critical difference!)"
- "Configured PropertyNameCaseInsensitive = true to match Newtonsoft default case-insensitive behavior"

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rubric item claims PropertyNameCaseInsensitive should be configured "to match Newtonsoft default case-insensitive behavior", but Newtonsoft.Json is case-sensitive by default, not case-insensitive.

This rubric item propagates the same incorrect information as the skill content and should be corrected or removed.

Suggested change
- "Configured PropertyNameCaseInsensitive = true to match Newtonsoft default case-insensitive behavior"
- "Discussed PropertyNameCaseInsensitive and how it compares to Newtonsoft's default case-sensitive behavior"

Copilot uses AI. Check for mistakes.
| **Number in string** (`"123"`) | Coerced automatically | **Throws by default** | Deserialization breaks! |
| **Enum serialization** | Numeric by default | Numeric by default | Same ✓, but converter syntax differs |
| **null → non-nullable value type** | Sets to default(T) | **Throws exception** | Breaks on dirty data |
| **Case sensitivity** | Case-insensitive | **Case-sensitive by default** | Property matching breaks |

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The claim that Newtonsoft.Json is "case-insensitive" by default is incorrect. Newtonsoft.Json is case-sensitive by default during deserialization, just like System.Text.Json.

Both libraries require explicit configuration to enable case-insensitive property matching (Newtonsoft uses MissingMemberHandling or custom settings, System.Text.Json uses PropertyNameCaseInsensitive = true).

This row should be corrected to indicate that both libraries are case-sensitive by default.

Suggested change
| **Case sensitivity** | Case-insensitive | **Case-sensitive by default** | Property matching breaks |
| **Case sensitivity** | **Case-sensitive by default** | **Case-sensitive by default** | Same by default; configure explicitly for case-insensitive matching |

Copilot uses AI. Check for mistakes.
}
```

Also show me how to configure the JSON options globally to match Newtonsoft.Json's default behavior.

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prompt asks to "match Newtonsoft.Json's default behavior", but this will lead to incorrect configuration guidance since the skill content incorrectly describes Newtonsoft.Json's default behavior (claiming camelCase and case-insensitivity as defaults).

The prompt should be revised to ask for common migration patterns or specific behavioral compatibility rather than "default behavior".

Copilot uses AI. Check for mistakes.
- "Changed [JsonExtensionData] Dictionary value type from JToken to JsonElement (critical difference!)"
- "Configured PropertyNameCaseInsensitive = true to match Newtonsoft default case-insensitive behavior"
- "Mentioned AllowTrailingCommas and/or ReadCommentHandling for compatibility"
- "Warned about behavioral differences (default casing, strict parsing)"

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rubric expects warnings about "default casing" as a behavioral difference, but since both libraries use the same default casing (property names as-is, typically PascalCase), this warning would be misleading.

The rubric should focus on actual behavioral differences such as strict JSON parsing, numbers-as-strings handling, and trailing commas/comments.

Suggested change
- "Warned about behavioral differences (default casing, strict parsing)"
- "Warned about behavioral differences (strict parsing, numbers-as-strings, trailing commas/comments)"

Copilot uses AI. Check for mistakes.

| Pitfall | Solution |
|---------|----------|
| Forgetting `PropertyNameCaseInsensitive = true` | Deserialization silently returns default values for all properties |

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pitfall "Forgetting PropertyNameCaseInsensitive = true" implies this is a required configuration to match Newtonsoft.Json behavior, but this is not accurate. Both libraries are case-sensitive by default.

This pitfall should be reworded to clarify that PropertyNameCaseInsensitive is only needed if the previous Newtonsoft.Json configuration explicitly enabled case-insensitive deserialization, not as a default requirement for all migrations.

Suggested change
| Forgetting `PropertyNameCaseInsensitive = true` | Deserialization silently returns default values for all properties |
| Assuming case-insensitive property matching without configuring it | If your previous Newtonsoft.Json settings enabled case-insensitive property names, set `options.PropertyNameCaseInsensitive = true` in `JsonSerializerOptions`; otherwise both serializers are case-sensitive by default and differing JSON/property casing will deserialize to default values. |

Copilot uses AI. Check for mistakes.
static void ConfigureJsonOptions(JsonSerializerOptions options)
{
// Match Newtonsoft.Json default behavior:
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; // Newtonsoft default

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "Newtonsoft default" on line 67 is incorrect. Newtonsoft.Json does not use camelCase by default for property naming. It uses the property names as-is (typically PascalCase for C# properties). CamelCase requires explicit configuration via CamelCasePropertyNamesContractResolver.

This comment should be removed or corrected to indicate this is a common convention, not a Newtonsoft default.

Copilot uses AI. Check for mistakes.
@mrsharm

mrsharm commented Feb 25, 2026

Copy link
Copy Markdown
Member Author

Skill Validation Results — migrating-newtonsoft-to-system-text-json

Skill Test Baseline With Skill Δ Verdict
migrating-newtonsoft-to-system-text-json Migrate model with Newtonsoft.Json attributes to System.Text.Json 4.0/5 4.3/5 +0.3

Overall improvement: +10.8% (3 runs, not statistically significant)

Model: claude-opus-4.6 | Judge: claude-opus-4.6

1 similar comment
@mrsharm

mrsharm commented Feb 25, 2026

Copy link
Copy Markdown
Member Author

Skill Validation Results — migrating-newtonsoft-to-system-text-json

Skill Test Baseline With Skill Δ Verdict
migrating-newtonsoft-to-system-text-json Migrate model with Newtonsoft.Json attributes to System.Text.Json 4.0/5 4.3/5 +0.3

Overall improvement: +10.8% (3 runs, not statistically significant)

Model: claude-opus-4.6 | Judge: claude-opus-4.6

@mrsharm mrsharm changed the title Add migrating-newtonsoft-to-system-text-json skill (+13.8% eval improvement) Add migrating-newtonsoft-to-system-text-json skill Feb 25, 2026
mrsharm and others added 2 commits February 25, 2026 06:00
…LL.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…LL.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@mrsharm

mrsharm commented Feb 26, 2026

Copy link
Copy Markdown
Member Author

Any feedback here? @ericstj @mcastro-x?

…LL.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@jeffschwMSFT
jeffschwMSFT requested a review from artl93 March 2, 2026 16:05
@mrsharm mrsharm closed this Mar 4, 2026
moesac0970 pushed a commit to moesac0970/skills that referenced this pull request Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants