Skip to content

[file-diet] Refactor Json.cs — split serializer and deserializer registrations into focused partial-class files #9017

@Evangelink

Description

@Evangelink

Overview

The file src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs has grown to 789 lines, making it harder to navigate and maintain. The vast majority of that bulk lives inside the single constructor, which inline-registers every type-specific serializer and deserializer for the JSON-RPC protocol. This task splits those registrations into focused partial-class files while keeping the core machinery in one place.

Current State

  • File: src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs
  • Size: 789 lines
  • Language: C#
  • Location: Microsoft.Testing.Platform — the JSON-RPC serialization layer used by server mode
Structural Analysis
Lines Content
17–350 Constructor: serializer registrations for JSON-RPC envelope types (RequestMessage, ResponseMessage, NotificationMessage, ErrorMessage) plus all response-args types (InitializeResponseArgs, ServerCapabilities, ServerTestingCapabilities, TestNode, TestNodeStateChangedEventArgs, LogEventArgs, TelemetryEventArgs, ProcessInfoArgs, AttachDebuggerInfoArgs, TestsAttachments, RunTestAttachment, ...)
350–365 Constructor: primitive-type serializers (string, bool, int, double, Guid, DateTime, DateTimeOffset, ...)
367–630 Constructor: deserializer registrations (RpcMessage dispatch, InitializeRequestArgs, DiscoverRequestArgs, RunRequestArgs, TestNode, CancelRequestArgs, ExitRequestArgs, ErrorMessage, ...)
632–649 SerializeAsync(object) — public async entry point
651–655 Deserialize<T>(ReadOnlyMemory<char>) — public entry point
657–684 Bind<T>, TryBind<T>, TryArrayBind<T> — internal binding helpers
686–712 Deserialize<T>(JsonElement) — core deserialization dispatch
714–777 SerializeAsync(object?, Utf8JsonWriter) — core serialization dispatch
779–788 ValidateJsonRpcHeader — static validation helper

Refactoring Strategy

Use C# partial classes to split the large constructor body into static helper methods, each living in its own file. The constructor delegates to these methods instead of inlining everything.

Proposed File Splits

  1. Json.cs (~150 lines)

    • Contents: class declaration, fields, constructor (now just calls RegisterDefaultSerializers + RegisterDefaultDeserializers + the user-override loops), and all core methods (SerializeAsync, Deserialize, Bind, TryBind, TryArrayBind, ValidateJsonRpcHeader)
    • Responsibility: Core serialization/deserialization engine
  2. Json.Serializers.cs (~340 lines) — partial class Json

    • Contents: private static void RegisterDefaultSerializers(Dictionary<Type, JsonSerializer> serializers) with all type → JsonObjectSerializer / JsonValueSerializer mappings
    • Responsibility: Default serializer registry for every JSON-RPC and test-protocol message type
  3. Json.Deserializers.cs (~300 lines) — partial class Json

    • Contents: private static void RegisterDefaultDeserializers(Dictionary<Type, JsonDeserializer> deserializers) with all type → JsonElementDeserializer / JsonCollectionDeserializer mappings
    • Responsibility: Default deserializer registry for every JSON-RPC and test-protocol message type

Implementation Guidelines

  1. Preserve Behavior: All existing functionality must work identically after the split — purely structural
  2. Maintain Public API: No changes to any public or internal signatures
  3. Test After Each Split: Run the MTP unit tests after each incremental file extraction
  4. One File at a Time: Extract serializers first, then deserializers, so each step is independently reviewable
  5. Keep Namespace: All files use namespace Microsoft.Testing.Platform.ServerMode.Json;

Acceptance Criteria

  • Original Json.cs is split into three focused partial-class files
  • Each new file is under 350 lines
  • All MTP unit tests pass after refactoring
  • No breaking changes to public or internal API surface
  • Constructor delegates to the new static helper methods

Priority: Medium
Effort: Small (mechanical extraction, no logic changes)
Expected Impact: Improved code navigability, easier future extension of the serializer registry, reduced merge conflicts when adding new message types

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Daily File Diet workflow.{ai_credits_suffix} · [◷]( · )

  • expires on Jun 12, 2026, 7:49 PM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions