>> Do you care about JSON?
In this case you should watch today's episode
because we'll talk about our a
new System.Text.Json API, and .NET Core 3.0.
[MUSIC]
>> Welcome to ON .NET.
My name is Emo Landreth.
I'm a Program Manager on the ON .NET platform
team and with me today is?
>> My name is Ezra Khan, and I'm a .NET
developer on the .NET Core BCL team.
>> That's awesome. What is the BCL?
>> So BCL is the built-in Base Class Library that comes
with the .NET Framework that had been installed.
>> That sounds cool. I think I've used it before at some point.
So what do you want to talk about today?
>> So I want talk about today the JSON library
that we have been working on for
the last six months or a year
working that's coming in as part of .NET Core 3.0.
So it's built in part of Core 3.0.
So you don't have to worry about adding
extra package reference or any other dependencies.
>> So when you say a JSON library, what does it roughly mean?
What do we cover like, what features do we offer?
>> So for the JSON library,
we are covering MVPs effectively,
we have the digital Serializer, Deserializer,
JSON document so you can have random access and
query APIs and the low level APIs reader and writer.
>> That's awesome. And you say MVP you
mean like a Minimum Viable Product.
>> That's right. Yes. So we'd like to scope down and
get the most commonly used scenarios working.
We wanted to make sure that the feature set is tenable.
>> Makes sense. So when we talk about JSON.
We cannot really not talk about JSON.NET which is the library
that pretty much everybody who has ever done
JSON and .NET has been using.
So how is the library that we are
building different from JSON.NET?
>> The main difference is that we emphasize performance from
the ground up and with wide leverage.
The new APIs have come up for in .NET
Core core specifically span the sequence.
So we wanted to make sure that
the APIs are focused on high performance,
low memory footprint and also natively support UTF-8.
That traffic is usually in UTF-8 encoded,
and James's library, Natalie works on strings and in Dark Net,
strings means UTF 16.
That's the primary difference.
>> Basically, by supporting native UTF-8,
you basically avoid the transcoding and memory allocations
of just transcoding from one to the
other just to parse on JSON, right?
>> Right, exactly.
>> That makes sense. You want to show us something?
How can I observe the new JSON library in the context of .NET Core?
>> So from the most high level,
if you have an ASP NET app,
effectively you will see this work under the covers.
So what I have here is just the API.
This is the template API that you get when you do .NET Newtonsoft.
If you have a rest endpoint,
you have a get request,
then under the covers we're
serializing and deserializing using Newtonsoft JSON library.
Before .NET Core 3.0, the default was just a Newtonsoft JSON.
Now the default is our library.
So just by being .NET Core, ASP.NET Core 3.0,
you would get that behavior.
So I could show you an example.
If I were to just run this API and query the endpoint,
this JSON payload is generated from our library.
>> So basically our library takes
this instance of the weather controller,
whatever this type is?
>> Yes.
>> It just serializes that into JSON.NET.
>> That's right. So I just create
a dummy object and
if you can see the values I'm showing up over here.
Now if you want to revert back to JSON.NET,
especially because there are some other features
that you might have to rely on.
For example in this case, if this
was a field rather than a property,
our library does not support fields today.
>> You're missing a semicolon.
>> Yes, good point. If I were to "Recompile" or
"Re-run," you would see most likely the temperature.
So if you saw previously we had the temperature and now we
don't because we changed temperature to a field.
But let's say your mall did have a field,
the way you would opt into it is we have
this integration package called My subnet MVC NewtonsoftJSON.
You add a back reference to that and on startup,
the thing you want to just do is in
your service connections add NewtonsoftJSON.
Once you have that, you should be able
to get back to the JSON.NET behavior.
You can get back to JSON. NET behavior and leverage
any other feature that you might want to use that
are missing in MVP API.
So temperatures are back.
>> Is the goal that we have to have basically parity with
JSON.NET on all of features
or will there be different feature set?
>> So the goal was never to have parity with
JSON.NET especially for some of the features
that we don't think make sense as built-in default for example.
For some of the other features, maybe like field support,
we would imagine getting them in the future.
>> Right. So part of the reason
why we shoot the preview is to get people to actually
use the preview and actually serialize
genuine types and actually see what
features people actually depend on and practice
so we can prioritize work accordingly.
Of course, you have opinions on
what we think many people are doing.
>> Right.
>> But it's very hard to get data on.
For example, do people use field versus properties very often.
That's very hard for us to find that out.
>> Yeah. So that's what I'm actually really interested in as well.
Then people started using the ASP.NET Core, see what breaks.
Right? What doesn't work as they were expected.
Getting the feel will be super useful.
Now going down the stack,
actually diving into the APIs themselves,
I have a few demos for serializer and then
all the way down to the low level reader
added APIs, which I want to show this..
So in the case of your CI's, I had this account type.
It has e-mails, it has a date and you have some rules.
What I've done is created this object.
Filled in some values, you have some date you have rules.
>> Right.
>> The most common scenarios people have is serialize MyType.
The code that you usually have to write is,
you have this deserializer type within the System types
JSON as you described deserialization name spaces.
You include those in your project
and you can code it to a string and parsing the account.
Now if you were to run that,
you should see the account payload show up.
This isn't really that human readable.
So let's try to make it indented and the way we do it is,
you just initialize adjacent
shares options and parse that in and we had
the capability to add indented.
That should be this with that.
That should be more human readable.
Now, of course, for passing data on the web,
you want to be compressed as possible
so you probably don't necessarily
care about human readability when
you're doing probability scenarios.
On the flip side, you have deserialirization
and it works similarly.
You have parsed APIs
on the serializer and you have deserializer.parse.
And let's add creating comma,
just for the sake of it,
and you can parse an option and our dream
comes true to support that as well.
In that case, there's
the e-mail from your account object that we need to serialize.
>> That's awesome. So basically,
that means almost all JSON
should be able to parse of our JSON library, right?
I think commas is not standards compliant or whatever that means.
>> Yeah.
>> It's very common. People want to do that.
>> That's right. So some of the things we
added because we observe people having
them a lot in their payloads is trailing commas and comments.
By default we don't support either of those
because by default we have to be actually compliant.
That's also a requirement that people have.
They want to be able to validate that
my incoming JSON is invalid and I truly want true.
So we didn't want enable those behavior by default.
>> That makes sense.
>> Now onto the additional document feature
that we have which allows
building up an extra structured Gardner type
that represent the JSON payload.
In my example, I have this.
For JSON, it's effectively a list
of students inside a class and their grades.
What I want to do is average out their grades.
So we need the JSON from the file.
What I want to do is now create this JSON document that we have.
When we have done this, we call JSON document.parse.
Parsing the JSON string.
In this case, if you notice again we have trailing
commas even though it's measuring.
You can parse in the real options to the document as well.
The interesting thing about this is,
this is building an in-memory
database or in-memory view of the JSON payload.
So it has zero allocations
especially for relatively small payloads.
>> Let this sink in for a moment because basically
when you say JSON document, to me,
the equivalent is like an XML document
or a Rawlsian syntax tree which by definition means it's
a tree structure that you have
a parent node and you have children nodes
and there's collections involved.
So how do you not have any allocations in this?
>> So that's part of the trade-off we made here which is why
to create a condensed view of the JSON and emphasize on,
how can we represent the JSON payload without allocation
but still be able to have reasonable pre-performance Core APIs.
The thing we realized is usually objects in JSON don't have a lot
of- the JSON themselves could be
large but they themselves don't have that many children.
So if you optimize for parsing but not for lookup,
then we can get this type of behavior.
The side effect of this is the document is read only.
So it isn't primarily driven
for people who want to- here's my JSON payload,
let me create an indexable or accessible object
out of it and then party on the other values.
So in this case we have, you can get probably properties,
parsing the property name and you have APIs that converts to
the JSON element which we already we got
into .NET types, like in this case double.
So what we're doing here is we go and look for
all of these students, get their grades.
Once, we have the value for that and convert them to a double.
This is where our application is doing.
Just summing them up and returning the average.
>> So these JSON like the strings that you
would do return there like the JSON element,
for example, that's not a class then?
That's basically a structure or something?
>> That's right. So again emphasis on reducing
allocations are coarser type
that represents each JSON token is awestruck.
Just a union type, it represents any JSON
whether it's an object or array or strings.
>> Right. So this way you can basically get
a structured view over the data but
you can't modify when it's read only.
>> Right. This is something that
we have to refine the first and I would love to see more feedback.
People want more read and write
capabilities and modifying capabilities
and we would consider that in the future.
>> Right. So when you see zero allocations,
this is literally like no matter how large the file is,
you literally allocate nothing.
Because at some point, there needs to be
some sort of index that is being built.
>> Right. So because we use the .NET Core under the covers,
effectively if you have a pillows
less than a megabyte, it doesn't allocate.
After that we start hitting the limitation
of the ripple and start allocating.
>> The re-poll technically
allocates to deduce it's an amortized costs so you have
like millions of requests that they don't grow linearly.
They must stay within the pool can handle.
Things like get larger than one megabyte,
we no longer allocate on the pool. Is that the idea?
>> Yes. So the pool under the covers up actually starts
allocating on as these theories.
But even then, our allocation size is proportion to
the distant payload rather than being five or
10X which will be required if you
had build up pre-order dictionary under the covers.
>> That's cool stuff.
>> Yes. Now, going back
to the lower level APIs which are the reader and writer.
So we have the low-level reader and writer APIs.
For example, we have JSON writer.
Now again, it works natively on UTF-8.
So therefore we call it UTF8JsonWriter
and these are very similar APIs that
you're probably used to like
WriteStartObject, WriteString, WriteNumber, etc.
It takes on the stream before writing to
a stream like a memory stream in this case.
It also takes in an array buffer writer which
is a new interface that'd be added into one.
So if you want more buffer management
and more buffer management control,
you would instantiate a new up I buffer writer and pass that in.
On the read side, we have UTF-8JsonReader,
and this takes UTF-8 data as span of byte.
This also similar, the code is similar to what you would write on
the Json.NET which is you have reader loop
via the switch for token types.
Our token types might be slightly different,
but generally it's you go to
the real loop and you
switch on where there is a PropertyName, String, etc.
Now, I want to show case this
just to have it run and see what it looks like.
So first, is the display for Writer.
We have indented so it looks like that.
Let me go back to what the Writer code looks like.
Again, this writer's disposable, see one machine we're using,
and let's say first we've written this data,
you want to read it,
and that would look as follows.
If you call it looks like we have the first token,
it's the only reader.
So it goes token, by token and the start object and
you get the property and if it's a date and you get
the string which is the value followed
by the temp, number, and then the EndObject.
Thus helps users to be able to read re-launch payloads,
because the reader is,
again no allocations and it just keeps reading forward.
>> Right. So when you say prof is better,
so can we actually substantiate this claim,
because otherwise this just as all we have faster
by how much like are we 2X faster?
Are we 100X faster,
what does it actually mean?
>> So one thing that we do a lot in our team,
is really do a lot of pro-testing.
A lot of the pro-testing, I mean it's all on GitHub.
So I will showcase of GitHub that I did pro-test for
serialization-deserialization for various models
that we found commonly in web apps.
If you notice here like most of the cases,
we are roughly 2X faster
than in terms of serialization
and deserialization from JSON.NET,
and when you compare the allocations,
we have this allocations there.
Now in this case, we are allocating because we have to allocate
the actual object at the end,
but in general it is same here,
we have different models.
This takes 1 plus 7 microseconds and
JSON.NET would end up taking almost two times the cost,
and here you can see the allocation differential up.
Similarly on the serialization side,
we have some of the models.
If you want see allies, we are 1.5 to 2X faster there as well,
and again emphasis on low allocations.
>> So these numbers seem really small,
I mean microseconds is not something that
most people measure in their day-to-day lives.
So why does this matter if you're
like 2X as fast for microseconds?
>> So I mean, this goes back to working with ASP NET,
and what we've seen is in their MVC processing,
there can be again up to a 20 percent through-put end-to-end.
I have some numbers to share for that as well.
So if we take a look at using system as JSON in ASP NET,
for the larger the payload,
the higher the gain for performance.
So requests per seconds went up from 7000 by using
JSON.NET to over 16,000
and we have smaller maybe for parent band as well.
So even in the end-to-end, some of
the higher level end-to-end scenarios in ASP .NET,
in MVC in the signal, MVC
substantial performance gains because of this.
>> Yeah, I mean, if you're like, I think we have
a partner being for example that does that well.
If you imagine you have millions of requests
or machines in the Cloud
that you have to support in order to get
a number of throughput per second,
if you can save 20 percent of your machines,
that is actually money you can measure.
Because you pay for your computer in the Cloud.
It's no longer free by your hardware is not free in that model.
>> That's right.
>> That is super cool. So one thing
that I would like to ask you too is,
so where can people get feedback,
how can they engage with us?
>> Right. So I think the best part,
since we're in NPV right now, the best avenue for
feedback is loggable in Corefx.
So Corefx, you can go to the GitHub Repo,
dotnet/corefx and file your issue.
>> That is also where the source code is for it.
>> That's exactly where the source code is
and you can find all sorts
of documentation and reporting guys and things like that,
if you look for a system like JSON.
It contains our roadmap, our design goals,
and so this is where we're talking about the feature requests,
a lot of the issues that might come up,
and this is where you actually really
want people to try this out and give us feedback,
so that we can make the part more
stable and leverage the scenarios that people have.
>> In fact, I think today, I mean,
by the time this video is going live,
it's probably no longer today, it's probably more like last week.
But today Preview6 Shift,
and in Preview6 that's when
MVC I think switched to use our cylinder by default.
I think in Preview5 it was still JSON,
I don't remember correctly.
So the idea is that you have people just to upgrade to Preview6,
take the existing ASP NET apps,
just let them see your license and see what no longer works.
>> That's right.
>> Ideally everything should work,
but I think that's overly optimistic,
given that we don't have the exact same feature set.
>> Again, some of the scenarios that don't work,
it's not like you would definitely take them in for
new feature release which is what
we're actually aiming for as well.
So yeah, if you were to go to.Net Core download link,
and you will always see the Preview6 Live.
You can go and grab that from there.
That's the first step that you want to do to try it
out, and if you're also,
by the way if you're running
ASP NET web apps that are on full framework,
you can reference the system here as
nugget package which is necessary tool compatible.
>> So it means I can reference from any platform that is
implementing to .NET center to all which is.
But my framework, I think we say 4.6.1 regularly,
it's 4.7.2 I think due to issues that we had,
but basically the library can be used for anybody,
do we get the same perfectly and everywhere or was it just for.
>> So the performance case are mainly high on core,
because that's what we're primarily optimized for,
and because that's all of the primitives,
unlike primitives like UTF-8 parser span etc are fostering core.
But the design algorithm
remains same across multiple implementations.
So things like the additional document not allocating,
they should work on both framework and core.
>> That is awesome. So if you like this,
go give us feedback, download the previews,
play with the beats, go to GitHub, file issues,
talk to us, we'd like to hear from you,
whether you like it or whether you don't like it.
Especially when you don't like it, we want to hear from you.
[MUSIC]