Laden...

Entities für WebApi-Ausgabe filtern

Erstellt von Daniel_3_17 vor 10 Jahren Letzter Beitrag vor 10 Jahren 987 Views
D
Daniel_3_17 Themenstarter:in
100 Beiträge seit 2008
vor 10 Jahren
Entities für WebApi-Ausgabe filtern

Hi,

wir erstellen derzeit ein Projekt mit ASP.Net Web Api und EF 5 (Code First) in Verbindung mit MySQL.

Das Problem das wir derzeit sehen ist, dass die Ausgabe nicht immer alle Eigenschaften der Entities beinhalten soll (z.B. Gehälter von Benutzern dürfen nur von Administratoren gesehen werden), gleichzeitig ist das Problem, dass verbundene Objekte auch zurückreferenzieren und auch dort soll nur das ausgegeben werden was der API-User sehen darf und für diesen API-Zugriff erforderlich ist.

Beispiel-JSON-Ausgabe, wenn man /users/ abfragt.


{
  "Id": 1,
  "Firstname": "Heinz",
  "Lastname": "Schmidt",
  "Password": "geheim", // soll nicht mit ausgegeben werden (wird natürlich in der Datenbank gehasht ;) )
  "AddressId": 1,
  "Address": {
    "Id": 1,
    "Street": "Bahnstraße 33",
  },
  "PermissionGroups": {
    "Name": "Finanzverwalter",
    "Users": {
      // Rück-Referenz mit allen Usern, die dieser Rechtegruppe angehören soll bei dieser Abfrage natürlich nicht gefüllt werden, allerdings schon, wenn per Api-Aufruf die PermissionGroups abgefragt werden.
    }
  },
}


Gibt es hierfür evtl. ein Pattern? Derzeit nutzen wir Delegates die pro Entity die Ausgabe per Select einschränken.

Danke schon mal!

Viele Grüße,
Daniel

16.835 Beiträge seit 2008
vor 10 Jahren

Eigene ViewModels / DTOs basteln, die nur die Eigenschaften haben, die übertragen werden sollen.

D
Daniel_3_17 Themenstarter:in
100 Beiträge seit 2008
vor 10 Jahren

Hi,

wer erstellt die DTOs? Für jeden API-Zugriff müsste es ja dann eigene Routinen geben, die die DTOs für den speziellen Fall erzeugen. (Beispielsweise benötigt API-Zugriff 1 auf die Personen nur die Person ansich, API-Zugriff 2 soll aber die Person inkl. der Adresse zurückgeben.

Würde dann jede Methode im API-Controller die DTO-Struktur für sich aufbauen?


PersonDto GetPerson(int id)
{
    var person = PersonDal.GetPerson(id);
    return new PersonDto()
    {
        Firstname = person.Firstname,
        Lastname = person.Lastname,
    };
}

PersonDtoWithPassword GetPersonWithPassword(int id)
{
    var person = PersonDal.GetPerson(id);
    return new PersonDtoWithPassword()
    {
        Firstname = person.Firstname,
        Lastname = person.Lastname,
        Password = person.Password,
    };
}

PersonDto GetPersonWithAdress(int id)
{
    var person = PersonDal.GetPerson(id);
    return new PersonDto()
    {
        Firstname = person.Firstname,
        Lastname = person.Lastname,
        Address = new AddressDto()
        {
            Street = person.Address.Street,
        },
    };
}

Je nachdem wie weit es verschachtelt ist, käme da recht viel doppelter Code zusammen, auch weil das andere API-Controller auch Funktionsteile davon brauchen. Oder ist das einfach so und hinzunehmen?

Dadurch, dass die eine API-Methode auch noch mehr Eigenschaften zurückgeben soll als die andere (das Passwort-Feld [ja, schlechtes Beispiel. 😄 ]), hätte man noch ein extra DTO. Oder sollte das Passwort-Feld bei Nichtverwendung einfach leergelassen werden?

Daniel

W
955 Beiträge seit 2010
vor 10 Jahren

Hallo,

* Du kannst es ja zu einigen DTO's zusammenfassen, Du mußt ja nicht für jede Controller/Action ein eigenes DTO bauen
* Schau Dir mal den Automapper an, damit sollte der Zuordnungscode wegfallen
* ich habe meist noch eine Service-Schicht zwischen Repositories und Controller, die übernehmen dann das Mapping der DTOs/ViewModels zu den Models

742 Beiträge seit 2005
vor 10 Jahren

Du kannst dir auch einen Generator schreiben. Bei mir sieht das dann so aus:

<schema>
<entity name="User" base="BaseEntity" note="Defines an user for the backend.">
<field name="Username" type="string" maxLength="100" minLength="4" required="true"
note="Username between 4 and 100 characters." />
<field name="Password" type="string" maxLength="100" minLength="20" required="true"
note="The encrypted password of the user." />
<field name="Mail" type="string" validator="Mail" required="true"
note="The mail address of the user." />
<field name="Salary" type="double" dataType="Currency" minValue="35500.0" maxValue="55000.0"
note="The salary of the user." />
</entity>

<model from="User" name="UserReadShortDTO" type="Read" includeDerived="true">
<include field="Id" />
<include field="Mail" />
<include field="Username" />
</model>

<model from="User" name="UserReadDTO" type="Read">
<exclude field="Salary" />
</model>
</schema>

Das heißt die Modelle und Entitäten werden in XML definiert und die Mapper und Klassen werden alle generiert.