Open mstern02 opened 7 months ago
Further testing has also revealed another bug the associated PR would fix:
When trying to read a bool or number from DDB when it does not exist will cause the dafault value (false
/ 0
) to be returned.
Email (string, pk) | MFARequired (bool) | LoginAttemps (number) |
---|---|---|
onefish@example.com | true | 2 |
twofish@example.com | empty | empty |
public class UserAuthConfig {
[DynamoDBHashKey]
public required string Email {get; set;}
public required bool MFARequired {get; set;}
public required int LoginAttempts {get; set;}
}
In this example the current implementation will read {"Email": "twofish@example.com", "MFARequired": false, "LoginAttempts": 0}
, instead of throwing an error, which seems like it could cause unforeseen bugs 😄
Required modifier does not disallow setting null (for nullable types or if nullable reference types are disabled).
Here's a perfectly valid code setting nulls:
var tst1 = new TestNullable { Value = null };
var tst2 = new TestNonNullable { Value = null };
class TestNullable
{
public required string? Value {get; set; }
}
#nullable disable
class TestNonNullable
{
public required string Value {get; set; }
}
Required modifier does not disallow setting null (for nullable types or if nullable reference types are disabled).
That is true (and good to know 😉 ), but required
still makes a difference when using System.Text.Json.JsonSerializer.Deserialize
:
using System;
using System.Text.Json;
var json = """{}""";
// Deserialized: User{ Email = null }
var optUser = JsonSerializer.Deserialize<OptionalUser>(json);
// Deserialization Error due to missing required property
var reqUser = JsonSerializer.Deserialize<RequiredUser>(json);
Console.WriteLine("{0}, {1}", optUser.Email, reqUser.Email);
#nullable disable
class OptionalUser {
public string Email {get;set;}
}
class RequiredUser {
public required string Email {get;set;}
}
It just seems unfortunate that the standard JsonSerializer
upholds the assumption that required
properties are not null, while DynamoDBContext
does not 🤔
the standard JsonSerializer upholds the assumption that required properties are not null
It doesn't. It fails because Email property is missing altogether. But it works fine if you pass the following json:
var json = """{"Email": null}""";
Anyway, my point is that it only makes sense to implement this feature along with handling nullable annotations as well.
Also, that would be a breaking change (unless it's opt-in by some config flag). So probably woudn't be approved until the major version bump (although not up to me to decide 😉 ).
Needs reproduction. This is more likely a feature request since it's requesting to support a new language feature.
Describe the bug
C# 11 introduced the required keyword to signal to the compiler that class members must be initialized using an object initializer.
This is also used by
System.Text.Json.JsonSerializer
to perform data validation at runtime.When retrieving a POCO from DynamoDB via
DynamoDBContext
this modifier is ignored, making it possible to create invalid objects accidentally.Take the following DynamoDB table storing users with their email and a display name.
Creating a
User
instance viaDynamoDBContext.ScanAsync<User>([])
can create an invalid object if a property markedrequired
does not exist on the corresponding item in DynamoDB, or is null, thus breaking expected guarantees.Expected Behavior
In the code snippet above I would expect the DynamoDB SDK to fail fast when encountering invalid values, instead of passing them along, which can cause the kind of unexpected behavior that
required
/#nullable
is supposed to guard against.Current Behavior
The SDK creates invalid objects at runtime.
Reproduction Steps
git apply
:It will fail when trying to invoke
ToUpper()
on a null value.Possible Solution
3277
Additional Information/Context
I consider this a bug, since
System.Text.Json.JsonSerializer
upholds these guarantees at runtime, whereasAmazon.DynamoDBv2.DataModel.DynamoDBContext
does not.AWS .NET SDK and/or Package version used
AWSSDK.DynamoDBv2 Git commit 23b74540be451eda8bb789980b4863bd8cc4241f (HEAD at time of writing)
Targeted .NET Platform
.NET 8
Operating System and version
Windows 11 22H2