Skip to content

Commit 1db3880

Browse files
authored
Add Serdes.DefaultOptions/Settings (#63)
1 parent 8f765f7 commit 1db3880

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ The `Unreleased` section name is replaced by the expected version of next releas
99
## [Unreleased]
1010

1111
### Added
12+
13+
- `NewtonsoftJson.Serdes.DefaultSettings`: Exposes default settings (for use with ASP.NET Core `.AddNewtonsoftJson`) [#63](https://github.com/jet/FsCodec/pull/63)
14+
- `SystemTextJson.Serdes.DefaultOptions`: Exposes default options (for use with ASP.NET Core `.AddJsonOptions`) [#63](https://github.com/jet/FsCodec/pull/63)
15+
1216
### Changed
1317
### Removed
1418
### Fixed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,46 @@ The respective concrete Codec packages include relevant `Converter`/`JsonConvert
114114
[`FsCodec.NewtonsoftJson.Serdes`](https://github.com/jet/FsCodec/blob/master/src/FsCodec.NewtonsoftJson/Serdes.fs#L7) provides light wrappers over `JsonConvert.(Des|S)erializeObject` that utilize the serialization profile defined by `Settings/Options.Create` (above). Methods:
115115
- `Serialize<T>`: serializes an object per its type using the settings defined in `Settings/Options.Create`
116116
- `Deserialize<T>`: deserializes an object per its type using the settings defined in `Settings/Options.Create`
117+
- `DefaultSettings` / `DefaultOptions`: Allows one to access a global static instance of the `JsonSerializerSettings`/`JsonSerializerOptions` used by the default profile.
118+
119+
# Usage of Converters with ASP.NET Core
120+
121+
ASP.NET Core's out-of-the-box behavior is to use `System.Text.Json`. One can explicitly opt to use the more ubiquitous `Newtonsoft.Json` via the `Microsoft.AspNetCore.Mvc.NewtonsoftJson` package's `AddNewtonsoftJson` by adjusting one's `.AddMvc)`.
122+
123+
If you follow the policies covered in the rest of the documentation here, your DTO types (and/or types in your `module Events` that you surface while you are scaffolding and/or hacking without an anti-corruption layer) will fall into one of two classifications:
124+
125+
1. Types that have an associated Converter explicitly annotated (e.g., DU types bear an associated `UnionConverter`, `TypeSafeEnumConverter` or `JsonIsomorphism`-based custom converter, custom types follow the conventions or define a `JsonIsomorphism`-based converter)
126+
2. Types that require a global converter to be registered. _While it may seem that the second set is open-ended and potentially vast, experience teaches that you want to keep it minimal._. This boils down to:
127+
- records arrays and all other good choices for types Just Work already
128+
- `Nullable<MyType>`: Handled out of the box by both NSJ and STJ - requires no converters, provides excellent interop with other CLR languages. Would recommend.
129+
- `MyType option`: Covered by the global `OptionConverter`/`JsonOptionConverter` (see below for a clean way to add them to the default MVC view rendering configuration). Note that while this works well with ASP.NET Core, it may be problematic if you share contracts (yes, not saying you should) or rely on things like Swashbuckle which will need to be aware of the types when they reflect over them.
130+
131+
**The bottom line is that using exotic types in DTOs is something to think very hard about before descending into. The next sections are thus only relevant if you decide to add that extra complexity to your system...**
132+
133+
<a name="aspnetnsj"></a>
134+
## ASP.NET Core with `Newtonsoft.Json`
135+
Hence the following represents the recommended default policy:-
136+
137+
services.AddMvc(fun options -> ...
138+
).AddNewtonsoftJson(fun options ->
139+
FsCodec.NewtonsoftJson.Serdes.DefaultSettings.Converters
140+
|> Seq.iter options.SerializerSettings.Converters.Add
141+
) |> ignore
142+
143+
This adds all the converters used by the default `Serdes` mechanism (currently only `FsCodec.NewtonsoftJson.OptionConverter()`), and add them to any imposed by other configuration logic.
144+
145+
<a name="asnetpstj"></a>
146+
## ASP.NET Core with `System.Text.Json`
147+
148+
The equivalent for the native `System.Text.Json` looks like this:
149+
150+
services.AddMvc(fun options -> ...
151+
).AddJsonOptions(fun options ->
152+
FsCodec.SystemTextJson.Serdes.DefaultOptions.Converters
153+
|> Seq.iter options.JsonSerializerOptions.Converters.Add
154+
) |> ignore
155+
156+
_As of `System.Text.Json` v5, the only converter used under the hood at present is `FsCodec.SystemTextJson.JsonOptionConverter()`_.
117157

118158
# Examples: `FsCodec.(Newtonsoft|SystemText)Json`
119159

src/FsCodec.NewtonsoftJson/Serdes.fs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ type Serdes private () =
99
static let defaultSettings = lazy Settings.Create()
1010
static let indentSettings = lazy Settings.Create(indent = true)
1111

12+
/// Yields the settings used by <c>Serdes</c> when no <c>settings</c> are supplied.
13+
static member DefaultSettings : JsonSerializerSettings = defaultSettings.Value
14+
1215
/// Serializes given value to a JSON string.
1316
static member Serialize<'T>
1417
( /// Value to serialize.
1518
value : 'T,
1619
/// Use indentation when serializing JSON. Defaults to false.
17-
[<Optional; DefaultParameterValue null>] ?indent : bool) : string =
20+
[<Optional; DefaultParameterValue false>] ?indent : bool) : string =
1821
let settings = (if defaultArg indent false then indentSettings else defaultSettings).Value
19-
JsonConvert.SerializeObject(value, settings)
22+
Serdes.Serialize<'T>(value, settings)
2023

2124
/// Serializes given value to a JSON string with custom settings
2225
static member Serialize<'T>

src/FsCodec.SystemTextJson/Serdes.fs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@ type Serdes private () =
99
static let defaultOptions = lazy Options.Create()
1010
static let indentOptions = lazy Options.Create(indent = true)
1111

12+
/// Yields the settings used by <c>Serdes</c> when no <c>options</c> are supplied.
13+
static member DefaultOptions : JsonSerializerOptions = defaultOptions.Value
14+
1215
/// Serializes given value to a JSON string.
1316
static member Serialize<'T>
1417
( /// Value to serialize.
1518
value : 'T,
1619
/// Use indentation when serializing JSON. Defaults to false.
17-
[<Optional; DefaultParameterValue null>] ?indent : bool) : string =
20+
[<Optional; DefaultParameterValue false>] ?indent : bool) : string =
1821
let options = (if defaultArg indent false then indentOptions else defaultOptions).Value
19-
JsonSerializer.Serialize(value, options)
22+
Serdes.Serialize<'T>(value, options)
2023

2124
/// Serializes given value to a JSON string with custom options
2225
static member Serialize<'T>
2326
( /// Value to serialize.
2427
value : 'T,
2528
/// Options to use (use other overload to use Options.Create() profile)
2629
options : JsonSerializerOptions) : string =
27-
JsonSerializer.Serialize(value, options)
30+
JsonSerializer.Serialize<'T>(value, options)
2831

2932
/// Deserializes value of given type from JSON string.
3033
static member Deserialize<'T>

0 commit comments

Comments
 (0)