-
-
Notifications
You must be signed in to change notification settings - Fork 447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
System.Text.Json support #1685
System.Text.Json support #1685
Conversation
3b7839a
to
9944183
Compare
6a8a4ad
to
523331a
Compare
public string StringField; | ||
|
||
public double Double { get; set; } | ||
public decimal Decimal { get; set; } | ||
public DateTime Date { get; set; } | ||
public DateTimeOffset DateOffset { get; set; } | ||
|
||
public float Float; | ||
public float Float { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's purposely a mix of properties and public fields to ensure that Marten works with both. If we do this, we just need to make sure there are tests specifically for Newtonsoft against public fields. So, ability to use a field as an identity and Linq querying.
Annoying, I know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
System.Text.Json requires explicit attribute on fields. I reverted the change and added attribute with a comment informing that's only needed for it.
@@ -74,7 +75,7 @@ public IGrammar QuestPartyShouldBe() | |||
} | |||
|
|||
[FormatAs("Members should be {Members}")] | |||
public string[] Members() | |||
public List<string> Members() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you have to do this? This wouldn't be serialized anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was done to align other changes, but it's reverted.
@@ -13,150 +13,88 @@ public class Root | |||
public interface IMonstersView | |||
{ | |||
Guid Id { get; } | |||
string[] Monsters { get; } | |||
List<string> Monsters { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STJ doesn't support arrays?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It wasn't supporting it properly when behind the Array was another type. It's fixed in the System.Text.Json 5, so I reverted the change here with the dependency added.
} | ||
|
||
public object FromJson(Type type, TextReader reader) | ||
public Task<T> FromJsonAsync<T>(Stream stream, CancellationToken cancellationToken = default) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should change the signature of this method to return a ValueTask
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used ValueTask in 1ef5e80.
|
||
public Task<object> FromJsonAsync(Type type, Stream stream, CancellationToken cancellationToken = default) | ||
{ | ||
return Task.FromResult(FromJson(type, stream)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably be using a ValueTask
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used ValueTask in 1ef5e80.
return _serializer.FromJson<T>(json); | ||
} | ||
|
||
public Task<T> ResolveAsync(DbDataReader reader, CancellationToken token) | ||
public async Task<T> ResolveAsync(DbDataReader reader, CancellationToken token) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And let's look to see about using ValueTask. Might also want the actual reading from the Stream to be async. We should look at how the ASP.net JsonFormatter uses STJ and see if it buffers data from the Stream or anything like that. Not saying this is necessarily wrong, but we should do our homework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's the right one - then it looks like is doing that the same way as we do: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonOutputFormatter.cs#L77 (plus they're doing additional serialisation from object that we don't want to do).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we should add method ToStream
and ToStreamAsync
to IQueryable
etc. Plus some custom output formatter that'll just return stream with proper encoding and response content type.
builder.Write(','); | ||
builder.Write(text.ReadToEnd()); | ||
builder.Write(text.GetStreamReader().ReadToEnd()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's reevaluate this one to see if there's a way to not have to read and create the string. See if there's a way to pipe the Stream bytes directly to the CommandBuilder
src/Marten/Marten.csproj
Outdated
@@ -31,6 +31,7 @@ | |||
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="4.11.1" /> | |||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="[2.1.0, 6.0.0]" /> | |||
<PackageReference Include="System.Text.Json" Version="5.0.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll make this an add on lib, right? Not be in the box?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This we need to discuss - in .NET 5 it's already built-in. I added NuGet, as built-in version in .NET Core 3.1 is too old and missing features. We can distribute that as separate package, but then maintainance might be harder as we'll have growing start of packages (NodaTime, Console, etc.).
@@ -29,7 +29,7 @@ public static QueryPlan ExplainQuery(this IManagedConnection runner, NpgsqlComma | |||
cmd.CommandText = string.Concat($"explain ({config} format json) ", cmd.CommandText); | |||
using (var reader = runner.ExecuteReader(cmd)) | |||
{ | |||
var queryPlans = reader.Read() ? serializer.FromJson<QueryPlanContainer[]>(reader.GetTextReader(0)) : null; | |||
var queryPlans = reader.Read() ? serializer.FromJson<QueryPlanContainer[]>(reader.GetStream(0)) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing TODO here might be to make the ISerializer interface take in the DbDataReader and index, then let each serializer to whatever they need to do. So you don't have to make the serializers conform to something that isn't idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored in be80fc6.
|
||
|
||
private readonly JsonSerializer _clean = new JsonSerializer | ||
private readonly JsonSerializer _clean = new() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we use the containment operator anymore, so this might no longer be needed. Not 100% sure about that though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to use ToJson
instead of ToCleanJson
but there were set of failing tests around querying interface types collection.
} | ||
|
||
public string ToJson(object document) | ||
{ | ||
var writer = new StringWriter(); | ||
ToJson(document, writer); | ||
using var stream = new MemoryStream(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we having to write to a stream like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted those changes and brought back old implementation after changing method signature with DBReader etc.
}; | ||
|
||
return _serializer.Deserialize<T>(jsonReader); | ||
} | ||
|
||
public T FromJson<T>(TextReader reader) | ||
public Task<T> FromJsonAsync<T>(Stream stream, CancellationToken cancellationToken = default) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to be using ValueTask.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to ValueTask in 1ef5e80. We should probably review if there are no places in our API that should return ValueTask (however, that's out of scope of this PR).
That looks like a ton of work. With the |
64965d4
to
c598cdc
Compare
0a13912
to
a64371b
Compare
….Text.Json happy (it does not allow to deserialize the public array property supported by the list backing field).
…ility between parser Added JsonPropertyName to QueryPlan to support also System.Text.Json
…o allow System.Text.Json work properly
Added JsonInclude for the field in `Target` test document class. Changed `Float` from field to property, as tests do not assume that it should be field.
Fixed Casing in System.Text.Json
…th SerializerType Used it in StoreOptions Added TestSetup to allow matrix tests on serializers Added TestsSettings to keep the test settings together Added SerializerTypeTargetedFact to allow skipping tests when feature is not supported for the particular serializer Added pipelines for System.Text.Json
…taReader and index params to allow serializers use its own the most pefromant way
Skipped unsupported test scenarios Added SerializerTypeTargetedTheory to skip theories for System.Text.Json
Unified streaming approach
a64371b
to
ceba441
Compare
Added serializer matrix to AsynDaemon and Schema testing projects
a0ada75
to
224c06c
Compare
@jeremydmiller @mysticmind PR is ready for the final review. |
{ | ||
using var jsonReader = new JsonTextReader(reader) | ||
using var textReader = reader.GetTextReader(index); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For later. If we took in the native Npgsql DbDataReader type instead, you get access to async versions of GetTextReader()
and GetStream()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My vote is to pull this in now.
My only comment beyond "thank you for doing all of this and I'm shocked at how much work it really required" is that we need to think seriously about either passing around NpgsqlReader
instead of DbDataReader
, or downcast (ick) as appropriate to use the async GetStreamAsync()
everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Apart from all the changes required to make STJ work, I really liked that you have spruced up the code with C# 9 lang features 👍
BTW, my changes pertaining to changing the code samples markers for migrating docs to vitepress looks to have added conflicts in few files, will address it and then merge the PR.
Added