-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Convert ComHost tasks to use System.Text.Json instead of Newtonsoft.Json #3087
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
Convert ComHost tasks to use System.Text.Json instead of Newtonsoft.Json #3087
Conversation
| <MicrosoftExtensionsDependencyModelVersion>2.1.0-preview2-26306-03</MicrosoftExtensionsDependencyModelVersion> | ||
| <NETStandardLibraryNETFrameworkVersion>2.0.1-servicing-26011-01</NETStandardLibraryNETFrameworkVersion> | ||
| <NewtonsoftJsonVersion>9.0.1</NewtonsoftJsonVersion> | ||
| <MicrosoftBclJsonSourcesVersion>4.6.0-preview3.19128.7</MicrosoftBclJsonSourcesVersion> |
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.
Do you need this? it should be part of runtime already
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.
ah we need that for full framework. @dsplaisted need your opinion, should we take system.text.json package dependency? And we should set up automatic insertion
| /// <summary> | ||
| /// Implementation of System.Buffers.IBufferWriter backed by ArrayPool.Shared. | ||
| /// </summary> | ||
| internal class ArrayBufferWriter : IBufferWriter<byte>, IDisposable |
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.
please add a comment like // TODO Remove once we have https://github.com/dotnet/corefx/issues/34894
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.
Honestly, spreading this to every repo is getting silly. Let's wait for it to be in. I don't understand the rush to use this API. Particularly because we can't actually remove N.J until NuGet does.
| <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" /> | ||
| <PackageReference Include="NuGet.ProjectModel" Version="$(NuGetProjectModelVersion)" /> | ||
| <PackageReference Include="NuGet.Build.Tasks.Pack" Version="$(NuGetBuildTasksPackVersion)" ExcludeAssets="All" /> | ||
| <PackageReference Include="Microsoft.Bcl.Json.Sources" Version="$(MicrosoftBclJsonSourcesVersion)" GeneratePathProperty="true"> |
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.
you should not need 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.
If we are going to use this package, we should only reference it for .NET Framework.
Also, why is this using a sources package instead of a library?
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.
You would need to reference it for both of the TFMs here (net472, netcoreapp2.0). The library is built-in on netcoreapp3.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.
I think we can move to 3.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 should not need to reference the nuget package, let me check that, rest is good
|
We need more discussion for adding system.text.json package. So i won't rush it to tonight's release 4 deadline |
| <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" /> | ||
| <PackageReference Include="NuGet.ProjectModel" Version="$(NuGetProjectModelVersion)" /> | ||
| <PackageReference Include="NuGet.Build.Tasks.Pack" Version="$(NuGetBuildTasksPackVersion)" ExcludeAssets="All" /> | ||
| <PackageReference Include="Microsoft.Bcl.Json.Sources" Version="$(MicrosoftBclJsonSourcesVersion)" GeneratePathProperty="true"> |
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 we are going to use this package, we should only reference it for .NET Framework.
Also, why is this using a sources package instead of a library?
|
I don't know where the package is that isn't the sources package, so I grabbed the sources package. Where is the library package located? |
| { | ||
| CustomAttributeValue<KnownType> data = attribute.DecodeValue(new TypeResolver()); | ||
| return (string)data.FixedArguments[0].Value; | ||
| return $"{{{(string)data.FixedArguments[0].Value}}}"; |
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 am curious, what's the reason for this change?
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.
These GUIDs should be wrapped in curly brackets. It's something I noticed they weren't while I was working on this.
|
|
||
| long prevBytesWritten = 0; | ||
|
|
||
| // Write some JSON, let's say an array of JSON objects in a loop |
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.
Comment doesn't match intent. Remove it?
| { | ||
| const int SyncWriteThreshold = 1_000; // Copy to stream after writing this many bytes | ||
|
|
||
| ArrayBufferWriter buffer = new ArrayBufferWriter(); |
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 is disposable. Add a using.
| string clsidMapText = File.ReadAllText(clsidMapPath); | ||
| using (StreamReader clsidMapReader = File.OpenText(clsidMapPath)) | ||
| using (JsonTextReader jsonReader = new JsonTextReader(clsidMapReader)) | ||
| JsonDocument clsidMap; |
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 needs to be disposed.
|
|
||
| private static void WriteClsidMap(Stream clsidMapFile, Dictionary<string, ClsidEntry> map) | ||
| { | ||
| const int SyncWriteThreshold = 1_000; // Copy to stream after writing this many bytes |
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.
How large is the map expected to be? 1_000 was just an arbitrary example in the sample, and primarily for async writes.
If you are flushing the the stream synchronously anyway, I would remove this threshold all together (and flush after you have written everything) or make it much larger.
If you expect to go beyond 1 MB when writing JSON here (and definitely if you go beyond 2 GB), then keep the sync threshold but make it larger.
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 find it quite troubling that we're expecting every consumer to think at this level. The BCL should provide a way to write Json to a Stream, IMHO.
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.
Where does 1 MB guideline for synchronous case come from? How would we know to choose that?
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 we were writing a big payload)
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.
The 1 MB guidelines is an implementation detail of using ArrayBufferWriter which is backed by the array pool. You can definitely continue to write up to 2 GB (and beyond until OOM), but beyond 1 MB, the array pool starts to allocate. That's why I suggested, that IF you were to set a sync threshold, 1 MB is reasonable. You don't have to, though, especially if allocations aren't a concern (writing to a growable stream without a sync threshold, for instance memory stream, has the same concern).
For performance oriented scenarios, we wanted to provide this fine grain control.
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 me rephrase. I wassaying "maybe I really want Serializer or DOM, but I am surprised that forward-only-writer-to-stream does not exist / is not directly supported".
JsonDocument is read-only today AFAICT from above. Are there plans to be able to build one up programatically and save like XDocument?
(I reach for XDocument a lot more than Xml serialization because I've been burned by serialization many, many times.)
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 did think that there was no JsonSerializer avaialble yet though, happy to see that is in.
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.
Are there plans to be able to build one up programatically and save like XDocument?
Not for 3.0, but something we are considering adding in the future based on feedback/user scenarios like yours.
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.
FWIW, your concerns and feedback have been heard and hopefully addressed with the recent Utf8JsonWriter changes! We ended up making some trade-off between perf and usability to enable the scenarios you mentioned, @nguerrera :)
https://gist.github.com/ahsonkhan/f6f30656717548212693e5eaa49cece5
dotnet/corefx#36961
Presumably, we should re-visit this PR given the new changes!
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.
Sweet! Thanks!
| if (prevBytesWritten > SyncWriteThreshold) | ||
| { | ||
| json.Flush(isFinalBlock: false); | ||
| buffer.CopyTo(clsidMapFile); |
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 believe there is bug in the sample which will cause issues here.
After flushing, you need to reset the json writer local by re-instantiating it.
If you are keeping this SyncWriteThreshold pattern here (which in general should not be needed), change it to the following:
foreach (KeyValuePair<string, ClsidEntry> clsid in map)
{
json.WriteStartObject(clsid.Key);
json.WriteString("assembly", clsid.Value.Assembly);
json.WriteString("type", clsid.Value.Type);
json.WriteEndObject();
if (json.BytesWritten > SyncWriteThreshold)
{
json.Flush(isFinalBlock: false);
buffer.CopyTo(clsidMapFile);
json = new Utf8JsonWriter(buffer, json.GetCurrentState());
}
}I'll fix the sample docs and call out that this pattern is mainly useful for async writes, not synchronous ones. Thanks!
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.
Btw, based on your porting effort, feedback/contribution to the porting guide would be most welcome so it can be improved :)
| <PackageReference Include="Microsoft.Bcl.Json.Sources" Version="$(MicrosoftBclJsonSourcesVersion)" GeneratePathProperty="true"> | ||
| <PrivateAssets>All</PrivateAssets> | ||
| </PackageReference> | ||
| <PackageReference Include="System.Memory" Version="4.5.2" /> |
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 super kean on more copy-local assemblies for the desktop build. We ran into issues with System.Memory and S.RC.Unsafe and mismatched versions in PresentationBuildTasks.dll. I don't know if it's worth adding more dependencies if we can't remove NewtonSoft.Json. And we can't because NuGet depends on it.
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 I'd wait for our dependencies to stop using newtonsoft.json. This is going to just create more DLLs to ship and load, not fewer.
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 we can move to 3.0.
The decision to port is up to you, but for clarity, if this moves to 3.0 and the built-in library is being used, then there won't be extra copy-local assemblies like System.Memory.
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 can't be 3.0 only. It can be 3.0 + 472. We have to run in Framework for VS msbuild
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.
Thanks for doing this, but I don't think we should take this yet. I see more dlls deployed and loaded, plus a bunch of copied code that comes with TODO debt. I don't see any actual value for now. At some point, the value will come but we're not there yet.
|
I'm going to close this for now since we aren't going to merge this in for quite a bit. I'll re-open it when we're closer to taking it. |
|
@ahsonkhan is there a way to serialize a |
|
Also @nguerrera @ahsonkhan the newest drop of |
|
Don't open a new PR yet. We need to think about the dependencies more carefully. `That isn't resolved yet. I'm happier with the new API shape, but that is orthogonal to the dependency issues. |
|
Maybe we should meet up? |
|
Sounds good to me. FYI I'm working remotely/oof until Tuesday. |
|
(And I'm out of office all of next week, and booked all day today.) |
|
@jkoritzinsky @nguerrera loop me in |
Not currently. It's WIP. See dotnet/corefx#37033 for concrete TKey, TValue. The polymorphic support is still pending.
Sure. Please setup a meeting sometime the week of April 29 or post Build :) cc @terrajobst |
…build 20191004.12 (dotnet#3087) - Microsoft.NET.Sdk.Razor - 3.1.0-preview1.19504.12
Fixes #3081
cc: @nguerrera @wli3