JSON support gets a major missing feature in .NET 7

Поделиться
HTML-код
  • Опубликовано: 19 окт 2024
  • Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I will introduce you to a new System.Text.Json feature coming in .NET 7 called polymorphism and type discrimination. It is currently available in preview 5 for everyone to try out and it makes working with the native JSON support, way more powerful and useful.
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasG...
    Follow me on Twitter: bit.ly/ChapsasT...
    Connect on LinkedIn: bit.ly/ChapsasL...
    Keep coding merch: keepcoding.shop
    #csharp #dotnet

Комментарии • 161

  • @andrewshirley9240
    @andrewshirley9240 2 года назад +76

    I don't like it for the same reason as everyone else- the parent needing to be aware of implemented types sounds like a huge anti-pattern and this approach probably shouldn't be supported at all. The approach with the typeinfo contract is a little better, but it's not really any less maintenance. As an example I've seen before, a video game may have an 'Item" class, that subtypes into "Consumable/Equipment/KeyItem/etc", and you may want to serialize an array of items. Having to go and catch *every single* item implementation in this registration in order to have it work properly seems awful.
    However, what the typeinfo contract option DOES open up is a reflection-based approach like we see in dependency injection helpers. I could totally imagine someone making a library that allows you to pass in a type and say "reflect to get all of its implementations, and register them with this serializer behavior." Then we just say "ConfigureInheritance(typeof(Item), [optionalUnmatchedBehavior], [optionalAssemblyForImplementations])" and all of the implementations are taken care of. I know why registering the parent on a child-per-child basis doesn't really work, since at the time of deserialization all the serializer knows is "parent type", and any solution involving the configuration of child elements would end up having to modify some global state or something.
    I DO understand why this needs to be locked down compared to how Newtonsoft does it, where they just have a single option that says "try and initialize any type I give it!" That was a big security hole and serialization attacks are a real thing, so I think making you register the exact expected types is a smart way around the issue.

    • @mindstyler
      @mindstyler 2 года назад +1

      this could be done with a source generator and be even better

  • @cverde1234
    @cverde1234 2 года назад +169

    I don't like having to couple a type to its derived types via an attribute. Decorating the sub-type with an attribute could work and be cleaner dependency-wise.

    • @seldomseen_78
      @seldomseen_78 2 года назад +19

      It looks like they got this one backward.

    • @davidmartensson273
      @davidmartensson273 2 года назад +18

      The problem with decorating the subtype is that it would need to search through all assemblies to find if there exist any type that are deriving since that cannot be found from the base type. And that could be even harder in case you have dynamic loading of assemblies for types that did not exist when you first start up the program. How often should you scan, every time you fail to find a type? That would be a performance problem very quickly. So that's why you would use you own type resolver and register that with JSON.

    • @ReazonIAm
      @ReazonIAm 2 года назад +4

      @@davidmartensson273 It can be code generated/cached on the startup(by just marking that some base class requires scanning) or at runtime on first type deserialization and have some support method to let the serializer know, that some(or exact) library was loaded and requires to be scanned/do it on loading if it has attributes. It might perform poorly if you have thousands of base types and you could argue this won't be convenient in case of assembly loading, but dynamic assemblies introduce enough problems (as a part of it's core desing) to be less convenient in almost all of the cases.
      Right now it conflicts with one the best and used design principle. I'm not sure how big of a problem this could be, but it's odd to say the least.

    • @davidmartensson273
      @davidmartensson273 2 года назад +1

      @@ReazonIAm I agree that is feels backwards, but I have seen the same solution in other serialisation libraries so I think its a "safe" solution.
      The thing with what Microsoft includes in the base libraries is that it must fit all use cases more or less unless you explicitly diverge from recommended solutions, thats why they sometimes avoid adding some convenient solution that other tool kits have so in this case I think they used this as it will work for any situation where it can be tried, it will explicitly not work for dynamically loaded types since the base type cannot know about those which solves that problem.

    • @davidmartensson273
      @davidmartensson273 2 года назад +3

      @@passenger9000 unless the class single purpose is serialization, in which case I think it can be appropriate.

  • @der.Schtefan
    @der.Schtefan 2 года назад +57

    The built-in Json was supposed to be kept very simple, fast, alloc free, etc. and now it adds more and more magic. I just hope they won't slow the core functionality down.

    • @Daniel-ml4jr
      @Daniel-ml4jr 2 года назад +10

      @@mw3653 You're embarrassing yourself.

    • @haukurorsson833
      @haukurorsson833 2 года назад +3

      @@mw3653 Are you OK?

    • @adinwashere
      @adinwashere 2 года назад

      @@haukurorsson833 nope

    • @haukurorsson833
      @haukurorsson833 2 года назад

      @@xybersurfer He said something along the lines of "It is open source so why don't you contribute to it instead of going on RUclips and posting such a lazy comment".

  • @Necromo7ph
    @Necromo7ph 2 года назад +15

    The solution is really simple for serialization.
    Point2d p = new Point3d { };
    string s = JsonSerializer.Serialize(p, p.GetType());

  • @rxuhwxx4tmly9xvcktcn2znpsx4
    @rxuhwxx4tmly9xvcktcn2znpsx4 2 года назад +8

    right on time after a high severity vulnerability was found in Newtonsoft.Json (GHSA-5crp-9r3c-p9vr)

  • @VitorSubs
    @VitorSubs 2 года назад +12

    I believe this could already be "solved" by passing the type of object as a second argument on the serializer

  • @Omego2K
    @Omego2K 2 года назад +42

    I don't like it. With this the base type needs to be aware of the derived type

  • @TuxCommander
    @TuxCommander 2 года назад +14

    Actually I would like to have the same TypeHandling experience as NewtonSoft JSON offers so I can deserialze Interface objects.

    • @TuxCommander
      @TuxCommander 2 года назад +1

      @@mw3653 everybody who wants to easy use NewtonSoft JSON in a minimal API...

  • @shahfaisal3923
    @shahfaisal3923 2 года назад

    Thank you so much for this video.
    Love and respect from Afghanistan.

  • @Krimog
    @Krimog 2 года назад +8

    Would it work (and have a Point3D object in memory) if at 6:51 instead of Deserialize you used Deserialize? I hope so because I think that's the point of the feature.

    • @ИванБармин-ю1т
      @ИванБармин-ю1т 2 года назад

      the same question, since now this feature looks meaningless, since it will be necessary to study the discriminator, and only after deserialize

    • @nickchapsas
      @nickchapsas  2 года назад +12

      It would. That's what I actually wanted to show working but I made a mistake in the video

    • @christophsiebert1213
      @christophsiebert1213 2 года назад +1

      @@mw3653 Just stop it.

  • @Matt23488
    @Matt23488 2 года назад +3

    Was just about to comment that it was frustrating that such a feature needs attributes. Glad to know support is coming for an alternative approach. I prefer to use as few attributes as possible.

    • @nickchapsas
      @nickchapsas  2 года назад +1

      Seems to be a trend. Most libraries offer non-attribute alternatives as they should, but not all of them do which can be really annoying

  • @OlegKosmakov
    @OlegKosmakov 2 года назад +3

    Cool, I was not happy when I had to implement the polymorphic deserialization myself. Had to deserialize it once just to find the type, and then deserialize it again to concrete type.
    I wonder how this new feature works under cover, does it always expect the type to be the first JSON node?

    • @nickchapsas
      @nickchapsas  2 года назад

      The type doesn’t have to be the first json property no since property ordering doesn’t matter in json and can’t be guaranteed between serialisers

    • @DmitryV_HF
      @DmitryV_HF 2 года назад

      What wrong with concrete deserialize? You want abstract JSON - use it, want strong type - use XML.
      This new feature not guaranty nothing. Only you know about target correct type, or prefix name. You use this json for self application and dont know about object type? If this external json, so you will be waiting reading prefixes inside data?

    • @davidmartensson273
      @davidmartensson273 2 года назад +1

      My guess is that it first deserializes to some generic dictionary/array structure and then builds an object from that. That way it can parse all properties and then decide what to do.
      I built something similar several years ago before we started using NewtonSoft and only had the old built in JavascriptSerializer ;).

  • @baka_baca
    @baka_baca 2 года назад +4

    Handling JSON in .NET still doesn't look great to me here and this isn't really what I would've wanted as a priority.
    Honestly, I would prefer to keep things simple by looking to how JavaScript handles JSON. We could have a Json.Parse(string json), and a Json.Stringify(obj data, JsonOptions options). Parse would deserialize the relevant properties to the passed in type even if camel cased, Stringify would serialize public properties to a json string using camel case by default (because honestly that is fairly standard and has been for a while) but you could still pass in options to override this. If you're having the problem described in this video, try using interfaces instead of inheritance or just stick with making a simple class which takes care of storing the deserialized json data and nothing else. Piling on all of this mess on top of the problem makes things even more complicated than before, not really convinced this is an improvement.

  •  2 года назад +3

    Always nice with alternatives, but most would probably just pick one of these:
    Point2d point3d = new Point3d();
    JsonSerializer.Serialize(point3d);
    JsonSerializer.Serialize((object)point3d);
    JsonSerializer.Serialize(point3d, point3d.GetType());
    One feature I don't think to many know about that is this one:
    [JsonExtensionData]
    public Dictionary ExtensionData { get; set; }

  • @Zapo9668
    @Zapo9668 2 года назад

    This is fantastic. I really need this feature asap.

  • @hodor2704
    @hodor2704 2 года назад +2

    Thanks Nick. probably I am missing something. why does it have to be so complex? if I serialize something, I should be able to serialize the actual instance without taking the reference type into account. If I deserialize something, I know what type I am expecting it to be. what am I missing?

  • @TodPalin
    @TodPalin 2 года назад +1

    I'm sitting here reading how people don't want to "break polymorphism" thinking why on earth you would cast a type back to its base and expect anything to treat it like you hadn't? You cast it to Point2D it's a Point2D, I don't want to serialise it as anything else.

  • @L1da77
    @L1da77 2 года назад +1

    Not sure what I think about this.
    If a Point3D is also a point2D through inheritance then why not just use the Point3D as a point2D instead of serializing back and forth?
    If I reduce a class to something else then I'd expect the extra data to be garbage collected. I'm probably missing something but this seems like an edge case imho 🤔

  • @AlanDarkworld
    @AlanDarkworld 2 года назад +1

    At long last, it was about time. Jackson had @JsonSubTypes for a while and it makes life so much easier. What I don't get in the video: why exactly does the *static* type of a variable matter when I pass it into the Json *serializer*? The serializer can just do a "typeof(input)" and use reflection from there. I see no reason why it would behave differently when my variable is Point2D or Point3D, it's about the content, isn't it? Deserialization is of course another matter.

  • @SlackwareNVM
    @SlackwareNVM 2 года назад +4

    I love the type resolver. I very much prefer it over adding attributes everywhere.

    • @SlackwareNVM
      @SlackwareNVM 2 года назад +1

      @@mw3653 We've had some very difficult to resolve issues that have come from attributes from 3rd party libraries. If you think you'll be fine, pick whatever option you like.

  • @zCri
    @zCri 2 года назад

    finally this is a thing, i was having so many issues with this

  • @shenlong3879
    @shenlong3879 2 года назад +4

    Like many others I'm not sure how I feel about the circular dependencies in there. Having a base class refer to something of a derived class kind of breaks polymorphism.
    Also for the first example if I treat a variable as a Point2D instead of a Point3D I usually don't want it to have the additional information of the Point3D unless I actually treat it as a Point3D again. The way I use variables already explicitly tells the code how I want it to be treated. One more reason why I use explicit types instead of vars. It may come in handy when you want all the data of a collection of a base class or interface with a wide variety of items but that should also be more explicit.

    • @abj136
      @abj136 2 года назад

      Indeed. I want the thing to behave like myPoint.JsonSerialize() which is a virtual call that is overridden by the most dervied type. I would think a simple [JsonSeriaize] attribute in each class that has attributes that should output would be a better way. And something similar to do the reverse.

  • @Denominus
    @Denominus 2 года назад

    I get why this is useful, but more as an escape hatch/kludge.
    I would strongly advise designing away from needing a type discriminator in your contracts.

  • @christianjansson6806
    @christianjansson6806 2 года назад

    What is that you say in the beginning of each video; "If you like abdobeidob content..."? Big fan of your channel and everything else is crystal clear! :-)

  • @phizc
    @phizc 2 года назад

    Does S.T.Json have the same problem with members too? E.g. a class that has a Point2D member, but it's assigned a Point3D. Would it get serialized as a Point2D?
    I've been making reader/writers for the 3D formats glTF and DAZ Studio's dson format, and I know it would bite me for dson. I think glTF is not polymorphic, bit dson definitely is. Luckily I haven't gotten around to making a writer for it, and I've been doing deserializing using JsonConverters.
    As for attributes, they should do it like Entity Framework. All of that should be possible to with a Context class and (model)builders.

  • @andytroo
    @andytroo 2 года назад

    is this available as a separate library, or do you have to bump your entire project to net7 to use it?

  • @franko6487
    @franko6487 Год назад

    I stumbled into this yesterday and lost 6 hours. I couldn't get arrays of types to deserialize. I was trying to couple it with StrongGrid which has a lot of polymorphic classes representing SendGrid events.
    I went back to rolling my own quick hack to serialize strongly typed events into my message queue and then out to Cosmos. This implementation has a lot of edges imo.

  • @TheMannihilator
    @TheMannihilator 2 года назад

    the type distinguisher via attribute is just like putting a property with the typename into the class and switch-case again when serializing/deserializing the type
    still not worse than the idea of listing all derived types as an attribute

  • @GuidoSmeets385
    @GuidoSmeets385 2 года назад +1

    I wonder how many injection attacks this will cause in the next few years. Type discriminators are great vectors for attacks like that. I hope they'll have an option to turn this off.
    Regarding wanting to use inheritance: just don't for DTO's. I've never in the past 10 years used inheritance in DTO's and not regretted it later. You can address almost all those issues easily with composition instead of inheritance. And for those rare cases where it's useful to enforce a set of shared properties among classes, use an interface.

    • @eipigamma
      @eipigamma 2 года назад

      What about when you have to represent a union type? Afaik, this is usually achieved through inheritance since we lake proper union type, or alternatively through some of the libraries that implement union type behavior as generics, but in both case, I guess deserializing would be hard without proper type annotation?

  • @robslaney3729
    @robslaney3729 Год назад

    @6:45 Even though you cast to a Point2D, you specified Point3D on the generic method

  • @ApacheGamingUK
    @ApacheGamingUK 2 года назад +2

    Much like everyone else here, this set off immediate alarm bells, and seems like one massive code smell.
    I assumed that the feature would simply allow you to add a generic type to the Serialise() method, and potentially, an optional mapping function as an optional parameter. So on line 10 in the example, you'd have "string point3dAsText = JsonSerializer.Serialize(point3d, SerialisationMapper.Default.MapImplicitly())". This would allow a lot more flexibility, whilst keeping the whole process as intuitive, and user friendly as possible. Not to mention that you resolve the backwards-heirarchy issues involved in adding volatile static annotation to what should be boilerplate code.

  • @MaxStagsted
    @MaxStagsted 2 года назад

    As always good video Nick. I don't like the "feature", like others have mentioned, decorating the parent class, just seems wrong, not your fault though.

  • @sunefred
    @sunefred 2 года назад

    Wow! I have been waiting for this. One of the must haves to move away from Newtonsoft. Fluent API would be nice though in top of the resolver mechanisms.

    • @sunefred
      @sunefred 2 года назад

      @@mw3653 Yeah, right!??? 1MB man =)

  • @noctavel
    @noctavel 2 года назад +7

    I didnt like the fact that you have to specify the derived attr on the base class. Its seems really nasty to me

    • @noctavel
      @noctavel 2 года назад

      @@mw3653 i won’t ;)

  • @darkelfasian
    @darkelfasian 2 года назад

    Hi Nick, what IDE are u using? It doesn't look like Visual Studio

    • @nickchapsas
      @nickchapsas  2 года назад

      It’s not visual studio. It’s Jebrains Rider

    • @leonov_am
      @leonov_am 2 года назад

      @@nickchapsasand it isn't for free, such a pitty

  • @bondarenkodf
    @bondarenkodf 2 года назад +4

    Great idea, but how to manage if you have configuration base class in one library and many sub-configuration classes in different DLL (including the future ones)?
    That attribute is a huge limitation.

    • @davidmartensson273
      @davidmartensson273 2 года назад +1

      That's when the resolver comes to the rescue if they implement it, or if they implement some way to directly register derived classes like JSON.RegisterDerivedClass()
      So all libraries then can do their own registrations

    • @telamarandrew2778
      @telamarandrew2778 2 года назад

      @@davidmartensson273 , it is so interesting that they can't implement smth working out of the box without registration. The default scenario which you can override or extend

    • @davidmartensson273
      @davidmartensson273 2 года назад

      @@telamarandrew2778 In theory they probably could but not without performance penalty. As I wrote in an other comment, when MS adds something to the base libraries they cannot leave undefined edge cases which means whatever they add either must even work for dynamically loaded assemblies or fail to compile for those cases. If you skipped those you could have something that will find any existing derived classes on compile and allow that but then if you add some new dynamically that would fail in runtime :/.
      And it is possible that you actually would NOT want all derived classes to serialize completely, you might have a derive class for internal use with properties you would not want stored and where you expect the current behavior of skipping all properties from derived classes.
      So it could also break the promise of backwards compatibility.
      For third party libs that could be acceptable, but not for default libs.

    • @davidmartensson273
      @davidmartensson273 2 года назад

      @@mw3653 for larger, partly legacy, you might not have the option to do the best and need to settle for good enough.

  • @skurtbert
    @skurtbert 2 года назад

    TY!

  • @Srhyle
    @Srhyle 2 года назад +3

    3:03 "some value" huh... 🤣🤣

  • @fred.flintstone4099
    @fred.flintstone4099 Год назад

    Is this useful for JSON-LD?

  • @ziauddinahmed2684
    @ziauddinahmed2684 Год назад

    I have a json response, it has mane nested object. The problem is it sometime give object array and sometime send just object. So its hard to deserealize. Example :
    Result : {
    Car :{
    "name":" bmw"
    "Model":" z"}
    }
    Result : {
    Car :[{
    "name":" bmw"
    "Model":" z"},
    {
    "name":" Toyota"
    "Model":" sls"}]
    }
    Is there anyway easy way to solve the issue. So it can be deserilize in a specific type. What i am doing is checking if its an array or object then converting each object to an array. Thanx in advance. 😊

  • @ibnfpv
    @ibnfpv 2 года назад

    This derived behavior of not printing the derived properties of the runtime object , is an decision behaviure the developers choose it is written on MSDN page , it was to prevent cases you print unwanted or sensitive derived class properties.
    The solution is very wierd to me with all the attributes /:
    Why there is no global / serilazation options for the expected behavior let the developer choose what good for his impl ,
    This is the default behavior of newtonsoft for example
    For now in older . Net versions the solution is to specify the Type in the deserialized method / deserialized to type object only then the runtime properties of the derived class will be written

  • @QwDragon
    @QwDragon 2 года назад

    6:26 Was it supposed to be Deserialize?

  • @glumboi9946
    @glumboi9946 2 года назад

    Could you make a video about copilot alternatives which are free?

  • @HenrryPires
    @HenrryPires 2 года назад +1

    What happen if Point2D it's in a dll that i included in my project? I can't just change it

    • @nickchapsas
      @nickchapsas  2 года назад

      That's where the solution shown in the end comes in handy

  • @carldaniel6510
    @carldaniel6510 2 года назад +3

    I love attributes in general, but I hate this use of attributes. Decorating the base class with information about the derived types is such an anti-pattern I'm surprised they even proposed it. The Type Resolver construct is essentially how Newtonsoft handles it, it's what everyone is accustomed to, and it doesn't pollute the base class with knowledge of the derived types. Win-win. If it was up to me, I'd drop the whole attribute-based approach and go with the type resolver solution alone.

  • @Алексей-я7т4б
    @Алексей-я7т4б 2 года назад

    Nice numbers

  • @egoegoone
    @egoegoone 2 года назад

    Still using newtonsoft in complex projects. Too many missing features missing from stjson. Though this is a Big hurdle out of the way.

  • @leonov_am
    @leonov_am 2 года назад +1

    Hello, I know another way to serialize derived type properly, is look like
    Point2D point3d = new Point3D(){ X = 10, Y = 15, Z = 20 };
    string point3dstr = JsonSerializer.Serialize((object)point3d);
    you just must explicit your type to object type.

  • @LuigWollknaeuel
    @LuigWollknaeuel 2 года назад +1

    Since I am working with complex objects and multiple layers of inheritance in my current Blazor project, I yeeted the Blazor HTTP client and reconfigured it to request and respond in BSON instead, using the MongoDB BSON Serializer. It comes with this functionality by default, and no attributes are required on base classes to include derived types.

  • @marcotroster8247
    @marcotroster8247 2 года назад

    What about Liskov Substitution Principle??? 😅🤔🙃

  • @realivanjx
    @realivanjx 2 года назад

    this hardly any problem for me since i hardly do inheritance especially for DAO

  • @figloalds
    @figloalds 2 года назад

    This is absolutely great, I might finally migrate from Newtonsoft Json after this

  • @thegnosticatheist
    @thegnosticatheist 2 года назад

    AYFKM? And I though only Unity JSON serializer had this issue...

  • @joephillips6634
    @joephillips6634 2 года назад

    This is exactly one reason why I'm stuck using newtonsoft in some places. Glad they're making this improvement

    • @calebvear7381
      @calebvear7381 2 года назад +1

      @@mw3653 dude why are you so salty?

  • @psdmaniac
    @psdmaniac 2 года назад +4

    Base type now knows about derived types :/ I think adding type field to json and deserialize them manually is still a better option.

  • @alexclark6777
    @alexclark6777 2 года назад +1

    I'm sure there's some motivation for requiring the attributes to be decorating the base type rather than individually applied to the derived types, but I'm not sure what those would be. Maybe to give ser/deser control to the author of the base type rather than letting derived consumers decide for themselves?

    • @GumbootMan
      @GumbootMan 2 года назад +1

      When deserializing you can pass in the base type as the type parameter, and if the JSON represents a derived type it will return that derived type. In this case the deserializer only has the base type and needs to know the possible derived types (and their discriminator strings). Attaching this information to the base type is straightforward and fast. Sure, you could fully scan the assembly for derived types, but that is slow and doesn't play well with assembly trimming. It sounds like they're planning on adding an API to register this same information, which would mean if you want the slow (but clean) way you can have it.

    • @alexclark6777
      @alexclark6777 2 года назад +2

      @@mw3653 Sorry for upsetting you.

  • @fl028
    @fl028 2 года назад

    Same thing I‘m using with Newtonsoft.Json TypeNameHandling and Interfaces. Very helpfull in WebApps :)

  • @andr6087
    @andr6087 2 года назад +1

    Thank you from Ukraine! 🇺🇦🇬🇧

  • @jamirkuhn5206
    @jamirkuhn5206 2 года назад

    What IDE he uses?

  • @xMrMiagix
    @xMrMiagix 2 года назад +1

    X = 4 Y = 20 Z = 69. Nice

  • @waynehamberg9248
    @waynehamberg9248 Год назад

    I don't like downsizing a class and having it upsized to something else. If a Point3D is somehow cast to a Point2D, I want that Z property to disappear and want an error generated when you have .Z. The "var" keyword is nice when you don't know the object you are returning but the overuse of "var" in my opinion is lazy development. I have found it lead to more bugs and makes things more difficult to maintain especially if you have to bring on additional developers.

  • @Servetnyk
    @Servetnyk 2 года назад

    What it would be, if I need to deserialize JSON that can be either type or array of type?
    What I mean. There is an (not mine) API and I send a Get request for items (e.g. Fruits).
    So if API has several items to return, it will return Fruits { { amount = 2 }, [ { item = Banana }, { item = Apple } ] }.
    But if API has the only one item to return, it returns Fruits { { amount = 1 }, { item = Banana } }.
    And you never know what result you will get.

    • @IbrahimKwakuDuah
      @IbrahimKwakuDuah 2 года назад

      Read the amount and decide what to do.

    • @Servetnyk
      @Servetnyk 2 года назад

      @@IbrahimKwakuDuah , well, I need to deserialized first. How? Then I need to create a converter to convert from type to array of type. To be possible to always return an array of type variable.

  • @shoutatme7362
    @shoutatme7362 2 года назад

    Or they could just do .GetType() on the object?? What were they thinking with this way of doing it?!?!?

  • @Wfmike
    @Wfmike 2 года назад

    Yes finally. Now we need Swashbuckle and or NSwag to add support in line with openapi oneof keyword.

  • @petrucervac8726
    @petrucervac8726 2 года назад +3

    Finally! Now I can delete the project I've build to solve this exact problem!

  • @RicusNortje
    @RicusNortje 2 года назад

    woohoo, been waiting literally years for this

  • @samsonojetade9127
    @samsonojetade9127 2 года назад

    So the base type has to know all about its derived typs now. Don't like it, they got this so backward.
    What's wrong with serializing based on the the runtime type of the object passed to the serializer?
    What happens when base type is inside another assembly? Or even an assembly that isn't yours to maintain?

    • @nickchapsas
      @nickchapsas  2 года назад

      The answer is at the end of the video

  • @nocgod
    @nocgod 2 года назад +6

    I hate polymorphic contracts, exactly because of ser/des
    But this implementation is pretty inelegant in comparison to what newtonsoft does

    • @nocgod
      @nocgod 2 года назад

      @@AbNomal621 that's exactly it, people don't give enough time to think out the contracts and db models. Ending up with crap solutions to handle this magic, while it would have been much easier to pay the price of planning in the beginning

  • @Ozuqam
    @Ozuqam 2 года назад +1

    Good they finally solved this issue but implementation looks like some one put it together during weekend

  • @dantecavallin8229
    @dantecavallin8229 2 года назад

    Seriously? When is microsoft gonna give up attributes? This should be the default feature at least.

  • @nordgaren2358
    @nordgaren2358 2 года назад

    Does this mean my big class of generic lists of other big classes of generic lists/arrays will get serialized properly, now?

    • @nordgaren2358
      @nordgaren2358 2 года назад

      @@mw3653 why? Game data is just like that...

    • @nordgaren2358
      @nordgaren2358 2 года назад

      @@mw3653 For example, modding Dark Souls games, just for the material data (like buffer layouts for each material, etc) is a 28k line xml file. This isn't all the data you need just for importing a 3d model, but it's a big chunk of it.
      A project I am working on wants to use that data, but we are already using json for similar data, so I wanted to just reserialize that class that holds the XML data as json, and I tried to do so with JsonSerialize in .net 6 and it actually gave me an empty json, which kinda sucked.
      The solution was to use Newtonsoft, but it would have been cool to just use the built in .net json library so as to not have to include another library (which is the reason to not use the class that the XML originally came from)
      So my question was half funny, but also kinda serious.

    • @nordgaren2358
      @nordgaren2358 2 года назад

      Unfortunately, reading the comments, it seems that my problem will probably persist, though, as it might be a problem with the implementation of the serializer. bummer. Anyways, I still have this video marked for watching, later.
      Thanks for the continued look into new language features, Nick!

  • @PinheiroJaime
    @PinheiroJaime Год назад

    All of it is not an issue in Newtonsoft for more than a decade

  • @infeltk
    @infeltk 2 года назад

    If JSON doesn't care about Z value that means that it is crap and they should use another lib. Point3D is new type and there is no reason to omit Z - it is normal property. And then appears Net 7 (that mean dude buy a new Visual Studio) and aaawesssome improvement - special magic @4:35. Am I wrong?
    Microsoft has much money I can''t write good library. It is not first time when Microsoft uses hack instead make better library in the past.

  • @gdargdar91
    @gdargdar91 2 года назад +2

    That pending update button on the top right corner might trigger OCD symptoms for some.

    • @gdargdar91
      @gdargdar91 2 года назад

      @@mw3653 Nobody asks you.

  • @kpanufnik
    @kpanufnik 2 года назад +1

    How...how this was not a thing in native JSON... I was using newtonsoft and jackson (xml hehe) and would not think that such feature could be missing...

  • @modernkennnern
    @modernkennnern 2 года назад +2

    Why is this not the default behaviour? If someome wanted to serialize an object, I'd imagine they'd want to get all the values inside it.

  • @spectrecular9721
    @spectrecular9721 Год назад

    4:20 - Technically, it serialized correctly because oftentimes after a lengthy 420 session, you fall asleep before you can 69 😏

  • @BinaryReader
    @BinaryReader 2 года назад +4

    Nope, handling union data structures is actually one of the worst aspects of nominal type systems, It's nice that .NET is trying to offer something here, but discriminators defined as attributtes is highly unintuitive. I actually find TypeScript discriminated unions to be far superior as rather than pushing descriminator fields into some common base class (which would have made for a better demo btw), TypeScript's structural type system simply allows you to group many types under a common alias type (where narrowing is achieved through control flow analysis, like if/switch). This is a far more natural representation of such types (and really important if you care about representing types in the same way across TS/C#).
    TypeScript also supports type intersection which can't be expressed at all in C# without multiple inheritance, (another consequence of C# having a nominal type system). In this respect, combinatorial types are extremely verbose and awkward to deal with in C#. There's just no good way to handle them without hordes of duplication.
    C#'s type system is way behind the curve, but had wondered if perhaps something could be done to layer the C# Dynamic Language Runtime with Structural Types (where C# borrows ideas from TypeScript).
    I sometimes wish Microsoft would just make a new .NET language that was a mix of TypeScript (Structural Type System, Primary Constructors, First Class Functions, Conditional Type Mapping / Computed Types) and all the good language features of C# (Strong Typing, Stack Alloc, Pointers, Reflection and LINQ) and maybe hygenic macros and opt in ownership and move semantics from Rust to help ensure thread safety.
    A language like that would be incredible.

  • @kazepis
    @kazepis 2 года назад

    When pretending that a string message got into the system and we want to deserialize it, I don’t understand why I have to pass the generic type to the deserializer since the string already contains the desired object type. I believe that is the case with Newtonsoft as of many years ago. You can deserialize to base class and have a derived class object.

    • @abj136
      @abj136 2 года назад +1

      Safety. What happens if somebody sends you an object and hacks the typename? To be safe you need to manage what type of object you accept.

  • @RasmusSchultz
    @RasmusSchultz 2 года назад

    I don't know why everything has to be solved with attributes or configuration factories. We have delegates. Just give me a simple way to specify a callback. But that's not The C# Way, I suppose - every simple little problem has to get solved by some impressive, masterful, Grand Architecture or framework. I guess somebody has to sell certifications, education and literature. 🙄

  • @gjoerulv
    @gjoerulv 2 года назад

    3:00 A Z value, just some value....

  • @mealloc
    @mealloc 2 года назад +1

    I'm not sold on the type resolver. Seems very intense and low level. I'd rather have a configuration option on the json serializer in my startup and enable type discriminator across the board without writing extra code, even for the types that doesn't need it.

  • @DragonSire
    @DragonSire 2 года назад

    If I define something 2D from 3D value....I want only the 2D data. So if I serialize it, I want it to stay as 2d. not serialize the underlying structure. I really don't see the benefit of this.

  • @DmitryV_HF
    @DmitryV_HF 2 года назад +3

    What wrong with concrete deserialize?
    Easy solution for problem - use overload method Serialize with concrete type of object. This is easy exctracted.
    JsonDerivedType attribute? Who guaranty what developer dont forget add this for all derived types? But if Point2D polimorphic too?

    • @DmitryV_HF
      @DmitryV_HF 2 года назад

      ​@@mw3653 But i very sad what people like you create alot "sugars" and "features" in .NET updates.
      Please read much comments with crytics to this JSON attribute. You glad to see much angry peoples? :)

  • @antonmartyniuk
    @antonmartyniuk 2 года назад

    I want built-in JSON serializer to be able to deal with TimeSpan and other structs which Newtonsoft Json does support

  • @goblelol
    @goblelol 2 года назад

    Why JsonDerivedType isn't generic? Since that is a new attribute, and generic attributes are introduced in .NET 7 already, then why not make a new attribute generic?

  • @anonimzwx
    @anonimzwx Год назад

    Should be automatically

  • @oscareriksson9414
    @oscareriksson9414 2 года назад

    But can't you just serialize the bytes? You are going to have to "know" the types when calling any way.. Maybe I just havent had the use case yet.

    • @oscareriksson9414
      @oscareriksson9414 2 года назад

      @@mw3653 wow. That's arrogant in so many levels, even more arrogant than the usual: 'I don't even care how a computer works'-arrogant. Using bytes to serialize to and from json with the built in tools is something I have done in .net 6, at home and at work. And like I said, the use case for the topic of the video I might just not have come across yet.

  • @GreenElectricEarth
    @GreenElectricEarth 2 года назад

    I am not a fan of attributes specially on this case, would be preferable to have like a setup of a property of the serializer like "lookupInheritance = true" so the resolver should be already something given by the serializer

  • @johnnyjosep
    @johnnyjosep 2 года назад

    69 days since it was DNS??? XD

  • @Mortizul
    @Mortizul 2 года назад

    As you're based in the UK, you should know that it's Zed not Zee.

  • @Kokujou5
    @Kokujou5 2 года назад +1

    this is not a feature that's a bug damnit XD nice fix^^

  • @xcoty3911
    @xcoty3911 2 года назад

    Yea I don't like this, it couples the 2 types and is sloppy.

  • @JS-1962
    @JS-1962 2 года назад

    You can already do this with a json converter

  • @domtremb5650
    @domtremb5650 2 года назад

    ok but honestly this version is pointless, there is no long term support for impar number versions. Latest long support would be .NET 6. Let's talk again when .NET 8 comes out

  • @antti4855
    @antti4855 2 года назад

    A type discriminator as a property value of a JSON object is complete a bad design and the worst thing that Newtonsoft have ever introduced. The same result is complete doable with pure language independent JSON with generic polymorphic type JsonConverter. Type discriminator is totally C# centric on Newtonsoft. Fortunately, net7 do not use class names etc. or other internals to C# but still it brakes JSON's cross platform design or makes deserialization inefficient. “$type” property must be the first property of on object so that deserializer can be efficient but there is no rule on JSON that order of properties can not be changed. For an example when JSON originates from C# goes through JS (browser) and comes bac to C#. A very common use case where JS can move "$type" to anywhere in the object.
    With type discriminator as a $type property:
    { “$type”: “fooBar”, “foo”: 1, “bar”: true}
    MUTCH BETTER ALTERNATIVE. Type discriminator as a property name:
    { “fooBar”: { “foo”: 1, “bar”: true} }
    This is not invented by me; It can be found for example from Elasticsearch API and CloudEvent event subscription filter expressions. But I have written a polymorphic json converters for it and it really works seamlessly. Unfortunate it also require that base type “knows” all derived types.

    • @phizc
      @phizc 2 года назад

      There are json based formats that use a property based type discriminator, e.g. DAZ Studio's dson format. The program isn't C#, so I doubt it's because of Newtonsoft.
      Having the ability to use that without having to write custom JsonConverters to read it is a good thing.
      I think glTF also uses property value based polymorphism on its extensions.
      Heck, even json schema uses property value based type discrimination.

  • @T___Brown
    @T___Brown 2 года назад

    This is exactly why we hated xml. Namespaces and types destroy serialization.

  • @petrowi
    @petrowi 2 года назад

    I've never used the .NET built-in JSON - too clunky and weird; it's always been the Newtonsoft one

  • @josephconnolly8493
    @josephconnolly8493 2 года назад

    Wanted to share as I spent way too much time trying to figure out how to use the MyPolymorphicTypeResolver (working in .net 7 RC-1):
    builder.Services.ConfigureHttpJsonOptions(options => {
    options.SerializerOptions.TypeInfoResolver = new MyPolymorphicTypeResolver();
    });
    app.MapPost("/points", (Point2D point) => {
    // point will be either 2d or 3d based on the discriminator
    });

  • @JustSammyyy
    @JustSammyyy 2 года назад

    4, 20, 69 :)