Migrating to 4.0
ToonNet 4.0 changes three defaults that let documents and responses do more than the code meant, so they now behave as System.Text.Json does, and fixes behavior that callers may rely on. This page lists what to check; the changelog has every change.
Non-Public Setters Are Not Set From Documents
Before 4.0, reading set any setter, private set included. Now only set and init setters are used:
public class Order
{
public decimal Total { get; private set; } // 3.x: set from the document; 4.0: not set
}
If a property with a non-public setter must be read, mark it [ToonInclude]:
[ToonInclude]
public decimal Total { get; private set; }
Such a property is now read-only for IncludeReadOnlyProperties = false (it is left out when writing then), unless it
has [ToonInclude].
Objects Are Written as Their Declared Type
Before 4.0, an object was written with the members of its runtime type. Now the type it is declared as decides: a
property's type, a collection's item type, a dictionary's value type, or the T of Serialize<T>.
string toon = ToonSerializer.Serialize(new Zoo { Star = new Dog { Name = "Rex", GoodBoy = true } });
public class Zoo { public Animal Star { get; set; } = new(); }
public class Animal { public string Name { get; set; } = ""; }
public class Dog : Animal { public bool GoodBoy { get; set; } }
4.0 writes the members of Animal:
Star:
Name: Rex
3.x, and 4.0 with SerializeRuntimeTypes = true, also write GoodBoy: true under Star.
To write derived members:
- declare the property as the derived type, or as
object(always written as its runtime type), or - set
ToonSerializerOptions.SerializeRuntimeTypes = trueto get the 3.x behavior everywhere (check that no derived type holds data a reader must not see).
Converters registered in the options for an item's or a dictionary value's declared type now apply to it, as they did for properties.
Required Members Are Required
RespectRequiredMembers is true by default: a document without a key for a required property throws
ToonSerializationException (The required property 'Email' is missing). Set it to false to keep the 3.x behavior:
var options = new ToonSerializerOptions { RespectRequiredMembers = false };
ASP.NET Core
ReadFromToonAsync (minimal APIs) now rejects bodies over 4 MB with 413 Payload Too Large, as the MVC formatter did.
For an endpoint that takes larger bodies, give it its own limit:
app.MapPost("/import", async (HttpRequest request) => await request.ReadFromToonAsync<Batch>())
.WithMetadata(new RequestSizeLimitAttribute(64 * 1024 * 1024)); // Microsoft.AspNetCore.Mvc
Source Generators
Use the 4.0 generator with ToonNet.Core 4.0, and rebuild; with a ToonNet.Core of another version the generator
reports TOON011 and generates nothing. Generated files have new names (with a hash of the type's
name), and code from older generators:
- is read with reflection when the options check required members (the default now), because it does not check them;
- does not tell the serializer its property types, so tables of its objects are planned through the tree.
Other Changes That Can Affect You
- A value tuple (
(int, string)) throwsNotSupportedExceptionwhen written; it used to become an empty object.Tuple<T1, T2>is still written asItem1/Item2. - A multidimensional array (
int[,]) throwsToonEncodingExceptionwhen written. - A number out of the range of an enum's underlying type is a
ToonSerializationException(300into abyteenum used to wrap around to 44). - Writing documents with an explicit separator throws
ToonSerializationExceptionwhen a document has a line equal to the separator. - In YAML, keys that differ only in their tag (
aand!!str a) are duplicate keys; explicit core-schema tags decide the type in any style (!!int "42"is the number 42) and accept only their values (!!int 1.5is an error);ToYamlquotes the strings YAML 1.1 readers would type (2001-12-14,12:30:00,0b101,1_000),<<,=, and strings with carriage returns or YAML 1.1 line breaks. ToonConvert.ToJsonwithIndented = trueindents arrays of numbers like other values (it wrote them on one line with a misplaced bracket).- The MVC output formatter no longer copies the charset of the
Acceptheader into the response (UTF-8 and UTF-16 only); request bodies of actions with their own[RequestSizeLimit]are limited by that limit, not by 4 MB. ToonNet.AspNetCoreno longer depends onMicrosoft.Extensions.Configuration.BinderandMicrosoft.Extensions.Options.DataAnnotations; reference them yourself if your code uses them through ToonNet.ToonYamlConverter.MaxAliasExpansionNodes,MaxAliasExpansionCharsandToonFormatterDefaults.MaxRequestBodySizearestatic readonlyfields instead of constants (they can no longer be used in attributes orswitchcases).- Members that use reflection in the JSON, YAML and ASP.NET Core packages are annotated for trimming and NativeAOT, so trimmed and AOT apps get a warning where they call them (see Source Generators – NativeAOT and trimming).
Error Messages
Messages that tests or log queries match may have changed:
| 3.x | 4.0 |
|---|---|
The constructor of X threw: <its message> | The constructor of X threw ArgumentException (the exception is the inner exception) |
The key 'Nmae' matches no property ... | The key matches no property ... (the key is in the path) |
Duplicate key 'a' | Duplicate key "a" |
$.user name.Id | $['user name'].Id (keys that are not identifiers; long keys cut to 64 characters) |
Rule message {value} of a string: x | "x" (quoted and escaped) |