Laden...

[erledigt] WebApi Serializing

Erstellt von Diräkt vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.318 Views
D
Diräkt Themenstarter:in
615 Beiträge seit 2009
vor 10 Jahren
[erledigt] WebApi Serializing

Hallo Leute

Ich versuche über die WebApi meine Entities (EF) anzubieten in einem möglichst "cleanen" json.
Das Problem ist unter "circular Reference" bekannt, aber eine Lösung habe ich nicht wirklich gefunden.

Der Json Serializer erlaubt einige Einstellungen:


var jsonSerializerSettings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                NullValueHandling = NullValueHandling.Ignore,
            };

Meine Test-DB:
=> Category -> Formel (1:N)
Ich frage hier immer die Formeln.Inculde("Category") ab.

Abfrage : http://localhost:50517/api/v1/Formel
Resultat: ( Screenshot 1 )
Bemerkung:
Die Formeln sind in der Flachenliste zwar verfügbar aber unter => Category => Formeln nochmals, teils mit dem "referenz Key".... Wie auch immer, clean ist das nicht.

Abfrage : http://localhost:50517/api/v1/Formel/1
Resultat: ( Screenshot 2 )
Bemerkung:
Wie auch immer, clean ist das nicht.


var jsonSerializerSettings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore,
            };

Abfrage : http://localhost:50517/api/v1/Formel
Resultat: ( Screenshot 3 )
Bemerkung:
Gleich wie Screenshot 1 , einfach das die Daten alle X mal wiederholt werden...

Abfrage : http://localhost:50517/api/v1/Formel/1
Resultat: ( Screenshot 4 )
Bemerkung:
Das wäre, was ich clean nennen würde

Als Test habe ich mal ne Methode geschrieben, so wie ich mit ".../Formel" vorstellen würde:

(Screenshot 5)


public dynamic GetCategoryWithFormel()
        {
            return DataStore.All<Formeln>().Select(data => new
                                                               {
                                                                   data.Id,
                                                                   data.Title,
                                                                   data.PositiveFeedback,
                                                                   data.NegativeFeedback,
                                                                   data.PicUrl,
                                                                   data.CategoryId,
                                                                   data.Category
                                                               });
        }

Muss ich jetzt wirklich alles von Hand umsetzen um einigermassen cleanes JSON zu erhalten? Kann mir jemand ein Tipp geben ?!

Beste Grüsse

Diräkt

1.002 Beiträge seit 2007
vor 10 Jahren

Hallo Diräkt,

deine localhost-URLs sind zwar nett gemeint, nützen uns hier aber nicht viel 😉.

Ich würde dir empfehlen, niemals direkt deine Domänenobjekte zurückzugeben, sondern immer ein Data Transfer Object (kurz DTO). Dieses enthält nur die Eigenschaften, die du zurückgeben möchtest, funktioniert also wie eine Whitelist. Dieses kannst du beispielsweise per Extension Method aus deiner Entity erzeugen und dann als Rückgabewerte der Action zurückgeben.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

D
Diräkt Themenstarter:in
615 Beiträge seit 2009
vor 10 Jahren

Hallo m0rius

Danke für Deine Antwort.

deine localhost-URLs sind zwar nett gemeint, nützen uns hier aber nicht viel 😉.

Dachte der lokale Horst sei überall !

Dieses kannst du beispielsweise per Extension Method aus deiner Entity erzeugen

Das stell ich mir nicht ganz so einfach vor, da ich z.B. mehrere Tabellen für ein DTO Object benötige, desweitern kann das original Entity dann ja verschiedene Ansichten haben, was wiederum bedeuten würde pro Ansicht eine DTO Klasse erstellen....

Die Daten werden als Json übermittelt. Da Frage ich mich wirklich ob ich auf das ganze nicht einfach verzichten kann und einfach dynamic verwende ?!


public dynamic GetCategoryWithFormel()
        {
            return DataStore.All<Formeln>().Select(data => new
                                                               {
                                                                   data.Id,
                                                                   data.Title,
                                                                   data.PositiveFeedback,
                                                                   data.NegativeFeedback,
                                                                   data.PicUrl,
                                                                   data.CategoryId,
                                                                   data.Category
                                                               });
        }

Dann versuch ich die Frage mal so zu formulieren, was für ein enormer Vorteil (neben der Typensicherheit) habe ich wenn ich 100 DTO Klassen erstellen muss ?

Beste Grüsse

Diräkt

16.807 Beiträge seit 2008
vor 10 Jahren

..., was wiederum bedeuten würde pro Ansicht eine DTO Klasse erstellen....

Korrekt. Und das, und auch nur das, wäre ein sauberer Weg.

Die Daten werden als Json übermittelt. Da Frage ich mich wirklich ob ich auf das ganze nicht einfach verzichten kann und einfach dynamic verwende ?!

Verwende JSON.NET und nicht die halbherzige .NET Implementierung.

Dann versuch ich die Frage mal so zu formulieren, was für ein enormer Vorteil (neben der Typensicherheit) habe ich wenn ich 100 DTO Klassen erstellen muss ?

  • Typersicherheit ist ein Muss und daher gibts keine Alternative.
  • Dass Entities per Service bekannt gemacht werden, ist ein Nogo.
  • dynamic ist langsam, sehr sehr langsam

PS: ich bringe hier mal wieder die MongoDB ins spiel.
Diese kann diese "gewollten Redundanzen" direkt speichern und das BSON quasi 1:1 dem Service anbieten; ohne irgendwelche Includes.
Hier sind DTOs viel leichter umzusetzen als via EF. Das EF ist einfach nicht für die (anderen) Ansprüche des Webs gemacht.

D
Diräkt Themenstarter:in
615 Beiträge seit 2009
vor 10 Jahren

Hallo Abt

Danke für Deine Antwort.

Verwende JSON.NET und nicht die halbherzige .NET Implementierung.

WebApi benutzt doch standardmässig json.net ?!

Dass Entities per Service bekannt gemacht werden, ist ein Nogo.

Dann frag ich mich wofür ich ein Repository benutze ?!
=> Oder sollte ich dann gleich bei der Basis-Implementierung von Get,GetAll... eine Transformation zu den DTO's implementieren ?

Edit:
=> Da WebApi ja kein WSDL "bietet", kommen die Daten beim Client ja eh nicht "typsicher" an, sondern da muss ja json / xml deserialisiert werden... Oder gibts da was wie "Generate Client Classes ?!... Sollte der Client .Net sein, scheint mir WCF einiges einfacher zu sein 😉

Beste Grüsse

Diräkt

P.S.
Sollte ich ein neues Projekt in nächster Zeit anfangen, werde ich mir dafür MongoDB mal im Detail anschauen und antesten...

16.807 Beiträge seit 2008
vor 10 Jahren

WebApi benutzt doch standardmässig json.net ?!

Ja natürlich. Habs nur mit JsonSerializerSettings verwechselt; hatte iwie im Kopf, das sei .NET.

Dann frag ich mich wofür ich ein Repository benutze ?!

Frag Dich doch lieber, wofür Du es nutzt 😉
Ein Repository ist dazu da, dass die Anwendung den Datenspeicher bzw. dessen inneres Leben nicht kennen muss. Ergo: Du kannst einfach so von mySQL auf MSSQL oder XYZ wechseln, ohne, dass die Anwendung angefasst werden muss.

DTOs sind aber dazu da, dass der Client abstrakt gehalten wird und er das innere Leben des Entities nicht kennen muss. Es ist einfach eine weitere Schicht.
Und nein, eine Entity kennt sein DTO nicht, und das DTO kennt die Entity nicht. Du musst hier einen Mapper bauen, DTO-> Entity bzw. Entity -> DTO.
Ja keine Schichten vermischen!!

Edit:

WebApi ja kein WSDL "bietet", kommen die Daten beim Client ja eh nicht "typsicher" an, sondern da muss ja json / xml deserialisiert werden

Das ist (im Prinzip) richtig; aber auch mit Json kann man "typisiert" arbeiten - nennt sich Bson. Wird aber nur zur konsistenten Datenhaltung verwendet, nicht zum Transfer. Darüber würde ich mir aber keine Gedanken machen. Das ist absolut gängig und OK so.
Nur sowas wieüber return object oder return dynamic auch nur nachzudenken... nix 😉

D
Diräkt Themenstarter:in
615 Beiträge seit 2009
vor 10 Jahren

Hallo Abt

Danke für Deine Antwort.

Und nein, eine Entity kennt sein DTO nicht, und das DTO kennt die Entity nicht. Du musst hier einen Mapper bauen, DTO-> Entity bzw. Entity -> DTO.

Es gibt doch da ein Projekt "AutoMapper", irgendwie ist mir das zwar nicht ganz geheuer 😉... Wenn DTO's soweit vebreitet sind, sollte es doch dafür eine "gängige" Lösung geben ? Oder wie machst du das ? 😃

Darüber würde ich mir aber keine Gedanken machen

Kann man die Server-Klassen ( in diesem Falle wären es ja dann die DTO's ) irgendwie vernüfntig anbieten ? (wenns ja kein WSDL gibt..)
Als .Net Entwickler ist ja WCF (auch..) wegen der Definition die "automatisch downloaded" wird so cool zu benutzen ?!

Wenn ich schaue wie die WebApi konsumiert werden, erstellt jeder wieder ein Model von Hand... grml (wir sind doch im Jahr 2013 oder hab ich was verpasst ?)

Beste Grüsse

Diräkt

16.807 Beiträge seit 2008
vor 10 Jahren

Oder wie machst du das ? 😃

Von Hand.

Wenn ich schaue wie die WebApi konsumiert werden, erstellt jeder wieder ein Model von Hand... grml (wir sind doch im Jahr 2013 oder hab ich was verpasst ?)

Wir sind im Web; da ist alles Metaoptimiert. Das ist schon richtig so.
Json ist das Mittel der Dinge.