Casting interfaces for deserialization in Json.NET
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Json.NET cannot instantiate an interface directly because interfaces are contracts, not concrete objects. If you deserialize into an interface type without concrete-type guidance, mapping fails. The practical solution is to supply type resolution explicitly through converters, metadata, or DTO mapping layers.
Why Interface Deserialization Fails by Default
Deserializer needs a concrete class with allocatable structure. Interface types such as IAnimal do not provide constructors or concrete member layout.
So this fails conceptually:
- target type is
IAnimal - payload describes one concrete subtype
- serializer has no rule for which subtype to instantiate
This is expected behavior and should be handled through explicit mapping strategy.
Strategy 1: Discriminator-Based Custom Converter
The safest general approach is a custom converter using a discriminator field such as kind.
This keeps allowed subtypes explicit and auditable.
Strategy 2: Metadata-Based Type Resolution
Json.NET also supports type metadata-based resolution. This can work in trusted internal systems but should be used carefully with untrusted payloads.
Metadata strategy is convenient, but security and compatibility implications must be reviewed before broad use.
Strategy 3: DTO First, Interface Mapping Second
In many production systems, the cleanest design is to deserialize into concrete transport DTOs, then map into domain interfaces. This separates wire format concerns from domain abstraction.
Benefits:
- no serializer-specific logic in core domain layer
- easier API versioning
- clearer testing of mapping rules
Example flow:
- deserialize JSON into
AnimalDto. - map
AnimalDtoto concrete domain object implementingIAnimal. - return interface to business logic.
This pattern often reduces framework lock-in.
Contract Design Recommendations
If you support polymorphic payloads, make discriminator field mandatory and documented. Do not infer type from optional field presence.
Good contract rules:
- one required discriminator key
- clearly defined subtype schema per discriminator value
- explicit behavior for unknown discriminator values
Unknown values should fail fast by default unless backward-compatibility policy says otherwise.
Testing Interface Deserialization
Add test coverage for:
- each supported subtype
- unknown discriminator handling
- missing discriminator handling
- round-trip serialization if required
Without these tests, subtype additions can silently break existing consumers.
For security-sensitive APIs, include tests that ensure unsupported type metadata is rejected.
Common Pitfalls
Deserializing directly to interface without converter strategy causes runtime mapping errors.
Using permissive type metadata with untrusted input can introduce security risk.
Spreading subtype mapping across many files makes polymorphic behavior hard to audit.
Assuming subtype inference from optional fields can break when payload evolves.
Summary
- Interfaces cannot be instantiated directly during Json.NET deserialization.
- Use explicit concrete-type resolution through converters or controlled metadata.
- Discriminator-based converters are usually the clearest and safest option.
- DTO-to-domain mapping can keep serializer concerns outside core abstractions.
- Test subtype resolution paths and unknown-type behavior explicitly.

