Json Serlization of Maybe
Closed this issue · 7 comments
How do I Json serialize a class with Maybe property?
Repro: Update the current unit test. CSharpFunctionalExtensions\CSharpFunctionalExtensions.Tests\MaybeTests
[Fact]
public void Deserialize_sets_no_value_on_maybe_none()
{
Maybe<MyClass> maybe = Maybe<MyClass>.None;
JsonSerializer.Serialize(maybe);
}
It throws.
System.InvalidOperationException : Maybe has no value.
Thanks.
Despite the provided issue relates to another Maybe
, I completely agree with the added justification.
There are some types that you would not expect to be serialized and deserialized. Action
, StringBuilder
, SqlConnection
, HomeController
, CancellationToken
, Task<T>
, ReadOnlySpan<T>
are just a few of these types. Moreover, these types in 99% of cases should also not be used as field and property types, they should act as local variables and as method parameters and return types.
The same applies to results/maybes/valueobjects. They should be used within your system, but they are not expected to cross system boundaries
So the solution here is simple
Maybe<MyClass> maybeClass = Maybe<MyClass>.None;
_ = JsonSerializer.Serialize(maybeClass.GetValueOrDefault());
// GetValueOrDefault returns default(T).
// It is null for reference types (which is totally fine),
// but for value types you need something a bit more sophisticated.
// Let's just convert Maybe<TValueType> to Nullable<TValueType>
// which is integrated to .NET type system and is well-known for serializers.
Maybe<MyStruct> maybeStruct = Maybe<MyStruct>.None;
_ = JsonSerializer.Serialize(maybeStruct.Match(value => value, () => default(MyStruct?))); // with inferred type
_ = JsonSerializer.Serialize(maybeStruct.Match<MyStruct?, MyStruct>(value => value, () => null)); // with explicetely provided type
Agree with @hankovich and with the commenter on the linked post. The general guideline here is this: use DTOs for intra-application communication. Maybe
and other types with "logic" are for inter-application use only.
I was using Maybe to express optional properties of the domain. For now, I went with C# null feature. example
EMail? AdditionalEmail;
I don't know if the course covered a prescribed way of exposing optional properties of the domain.
Off-topic: There is inefficient coverage on the usage of the Enum value object type. Hopefully, your new course will use it. It serialised to {id ='foo', name='bar'}. It is unclear to me why the enum has two properties. When I serialize enum Color, I only expect to see 'Red', or 'Green', etc. The id is an implementation detail irrelevant to the domain.
In the domain, it's better to have Maybe<Email> AdditionalEmail;
instead of EMail? AdditionalEmail;
. If you want to serialize the class somewhere, then you'd need to map it to a DTO, which you'd serialize instead of the domain class.
Regarding the enum class, there should be 2 versions, 1 with Id
and Name
and the other one with just an Id
. I haven't looked into the current implementation in-depth yet, it probably needs some refactoring.
The gist: Maybe class does not support serialization so we have to use a DTO class.