Jak używać obiektów transferu danych w ASP.NET Core 3.1

Obiekt transferu danych (powszechnie znany jako DTO) jest zwykle wystąpieniem klasy POCO (zwykły stary obiekt CLR) używanym jako kontener do hermetyzacji danych i przekazywania ich z jednej warstwy aplikacji do drugiej. Zwykle można znaleźć DTO używane w warstwie usług do zwracania danych z powrotem do warstwy prezentacji. Największą zaletą korzystania z DTO jest oddzielenie klientów od wewnętrznych struktur danych.

W tym artykule omówiono, dlaczego powinniśmy używać obiektów transferu danych i jak możemy z nimi pracować w ASP.NET Core 3,1. Aby pracować z przykładami kodu przedstawionymi w tym artykule, w systemie powinien być zainstalowany program Visual Studio 2019. Jeśli nie masz jeszcze kopii, możesz pobrać program Visual Studio 2019 tutaj. 

Utwórz projekt interfejsu API ASP.NET Core 3.1

Po pierwsze, utwórzmy projekt ASP.NET Core w programie Visual Studio. Zakładając, że w systemie jest zainstalowany program Visual Studio 2019, wykonaj czynności opisane poniżej, aby utworzyć nowy projekt interfejsu API ASP.NET Core w programie Visual Studio.

  1. Uruchom środowisko IDE programu Visual Studio.
  2. Kliknij „Utwórz nowy projekt”.
  3. W oknie „Utwórz nowy projekt” wybierz „Aplikacja sieci Web ASP.NET Core” z listy wyświetlonych szablonów.
  4. Kliknij Następny. 
  5. W oknie „Konfiguruj nowy projekt” określ nazwę i lokalizację nowego projektu.
  6. Kliknij Utwórz. 
  7. W wyświetlonym obok oknie „Tworzenie nowej aplikacji sieci Web ASP.NET Core” wybierz .NET Core jako środowisko wykonawcze i ASP.NET Core 3.1 (lub nowszy) z listy rozwijanej u góry.
  8. Wybierz „API” jako szablon projektu, aby utworzyć nową aplikację ASP.NET Core API. 
  9. Upewnij się, że pola wyboru „Włącz obsługę Dockera” i „Konfiguruj dla HTTPS” są odznaczone, ponieważ nie będziemy tutaj używać tych funkcji.
  10. Upewnij się, że uwierzytelnianie jest ustawione na „Brak uwierzytelniania”, ponieważ nie będziemy też używać uwierzytelniania.
  11. Kliknij Utwórz. 

Spowoduje to utworzenie nowego projektu interfejsu API ASP.NET Core w programie Visual Studio. Będziemy używać tego projektu do pracy z obiektami transferu danych w kolejnych sekcjach tego artykułu.

Dlaczego warto korzystać z obiektów transferu danych (DTO)?

Podczas projektowania i tworzenia aplikacji, jeśli używasz modeli do przekazywania danych między warstwami i wysyłania danych z powrotem do warstwy prezentacji, ujawniasz wewnętrzne struktury danych aplikacji. To poważna wada projektowa w Twojej aplikacji.

Oddzielając warstwy, DTO ułatwia życie podczas wdrażania interfejsów API, aplikacji MVC, a także wzorców przesyłania wiadomości, takich jak Message Broker. DTO to doskonały wybór, gdy chcesz przepuścić lekki obiekt przez przewód - szczególnie, gdy przepuszczasz obiekt przez medium o ograniczonej przepustowości.

Użyj DTO do abstrakcji

Korzystając z DTO, można wyodrębnić obiekty domeny aplikacji z interfejsu użytkownika lub warstwy prezentacji. W ten sposób warstwa prezentacji aplikacji jest oddzielona od warstwy usługowej. Jeśli więc chcesz zmienić warstwę prezentacji, możesz to łatwo zrobić, podczas gdy aplikacja będzie nadal pracować z istniejącą warstwą domeny. Podobnie możesz zmienić warstwę domeny swojej aplikacji bez konieczności zmiany warstwy prezentacji aplikacji.

Użyj DTO do ukrywania danych

Innym powodem, dla którego chciałbyś używać DTO, jest ukrywanie danych. Oznacza to, że za pomocą DTO można zwrócić tylko żądane dane. Na przykład załóżmy, że masz metodę o nazwie GetAllEmployees (), która zwraca wszystkie dane dotyczące wszystkich pracowników. Zilustrujmy to, pisząc jakiś kod.

We wcześniej utworzonym przez nas projekcie utwórz nowy plik o nazwie Employee.cs. Napisz następujący kod w tym pliku, aby zdefiniować klasę modelu o nazwie Employee.

Pracownik klasy publicznej

    {

        public int Id {get; zestaw; }

        public string FirstName {get; zestaw; }

        public string LastName {get; zestaw; }

        public string DepartmentName {get; zestaw; }

        public decimal Basic {get; zestaw; }

        public decimal DA {get; zestaw; }

        public decimal HRA {get; zestaw; }

        public decimal NetSalary {get; zestaw; }

    }

Zwróć uwagę, że klasa Employee zawiera właściwości, w tym Id, FirstName, LastName, Department, Basic, DA, HRA i NetSalary. Jednak warstwa prezentacji może potrzebować tylko Id, FirstName, LastName i Department Name pracowników z metody GetAllEmployees (). Jeśli ta metoda zwróci listę, każdy będzie mógł zobaczyć szczegóły wynagrodzenia pracownika. Nie chcesz tego. 

Aby uniknąć tego problemu, można zaprojektować klasę DTO o nazwie EmployeeDTO, która będzie zawierać tylko żądane właściwości (takie jak Id, FirstName, LastName i Department Name).

Utwórz klasę DTO w C #

Aby to osiągnąć, utwórz plik o nazwie EmployeeDTO.cs i napisz w nim następujący kod.

klasa publiczna EmployeeDTO

    {

        public int Id {get; zestaw; }

        public string FirstName {get; zestaw; }

        public string LastName {get; zestaw; }

        public string DepartmentName {get; zestaw; }

    }

Teraz, gdy model i klasy obiektów transferu danych są dostępne, możesz chcieć utworzyć klasę konwertera zawierającą dwie metody: jedną do konwersji instancji klasy modelu Employee na instancję EmployeeDTO i (odwrotnie) do konwersji instancji EmployeeDTO do instancji klasy modelu Employee. Możesz także skorzystać z AutoMapper, popularnej biblioteki mapowania obiekt-obiekt, aby zmapować te dwa odmienne typy. Możesz przeczytać więcej o AutoMapper tutaj.

Należy utworzyć listę w warstwie usług aplikacji i przywrócić zbiór z powrotem do warstwy prezentacji.

Niezmienność DTO

DTO służy do przenoszenia danych z jednej warstwy aplikacji do innej warstwy. Konsument DTO może być wbudowany w .NET / C # / Java lub nawet JavaScript / TypeScript. DTO jest często serializowany, dzięki czemu może być niezależny od technologii używanej w odbiorniku. W większości przypadków odbiorca danych nie musi modyfikować tych danych po ich otrzymaniu - najlepiej nie!

To klasyczny przykład wagi niezmienności. I właśnie dlatego DTO powinno być niezmienne!

Istnieje kilka sposobów implementacji niezmiennych DTO w języku C #. Można użyć ReadOnlyCollection lub niezmiennych typów kolekcji bezpiecznych dla wątków obecnych w przestrzeni nazw System.Collections.Immutable. Możesz skorzystać z typów rekordów w C # 9, aby zaimplementować również niezmienne DTO.

Projekt oparty na domenie oczekuje, że obiekty domeny będą niezmienne zewnętrznie. To dobry powód, aby uczynić Twoje DTO niezmiennymi, prawda?

Wyzwania związane z serializacją DTO

Powinieneś być w stanie bezproblemowo serializować / deserializować DTO, aby można go było przekazać dalej. W praktyce jednak może być konieczne rozwiązanie niektórych problemów serializacji podczas pracy z DTO. W rzeczywistej aplikacji może istnieć kilka jednostek lub klas modeli i każda z nich może zawierać wzajemne odwołania.

Załóżmy, że zbudowałeś system zarządzania frekwencją dla pracowników w Twojej organizacji. Zwykle w aplikacji może istnieć klasa o nazwie Employee, która odwołuje się do klasy User (tj. Pracownik jest użytkownikiem aplikacji), która z kolei odwołuje się do klasy Role. Klasa Role może odwoływać się do klasy Permission, która z kolei może odwoływać się do klas PermissionType i PermissionGroup. Teraz, gdy serializujesz wystąpienie klasy Employee, w końcu serializujesz również te obiekty. Łatwo zauważyć, że w niektórych skomplikowanych przypadkach może dojść do serializacji kilku typów.

Tutaj na ratunek przychodzi leniwe ładowanie lub ładowanie asynchroniczne. Jest to funkcja, która może pomóc w ładowaniu obiektów tylko wtedy, gdy zostaniesz o to poproszony. Aby uzyskać więcej informacji na temat wykonywania leniwego ładowania, możesz zapoznać się z moim artykułem na temat leniwej inicjalizacji w języku C #.

Obiekty transferu danych zazwyczaj nie zawierają żadnej logiki biznesowej - zawierają tylko dane. Niezmienność jest pożądaną funkcją podczas pracy z DTO. Istnieje kilka sposobów implementacji niezmiennych DTO. Omówię więcej na temat niezmienności w C # w późniejszym poście tutaj.

Jak zrobić więcej w ASP.NET Core:

  • Jak obsługiwać błędy 404 w ASP.NET Core MVC
  • Jak używać iniekcji zależności w filtrach akcji w ASP.NET Core 3.1
  • Jak używać wzorca opcji w ASP.NET Core
  • Jak używać routingu punktów końcowych w ASP.NET Core 3,0 MVC
  • Jak wyeksportować dane do programu Excel w ASP.NET Core 3,0
  • Jak używać LoggerMessage w ASP.NET Core 3,0
  • Jak wysyłać wiadomości e-mail w ASP.NET Core
  • Jak rejestrować dane w programie SQL Server w ASP.NET Core
  • Jak planować zadania przy użyciu Quartz.NET w ASP.NET Core
  • Jak zwrócić dane z ASP.NET Core Web API
  • Jak sformatować dane odpowiedzi w ASP.NET Core
  • Jak korzystać z ASP.NET Core Web API przy użyciu RestSharp
  • Jak wykonywać operacje asynchroniczne przy użyciu Dapper
  • Jak używać flag funkcji w ASP.NET Core
  • Jak używać atrybutu FromServices w ASP.NET Core
  • Jak pracować z plikami cookie w ASP.NET Core
  • Jak pracować z plikami statycznymi w ASP.NET Core
  • Jak używać oprogramowania pośredniczącego ponownego zapisywania adresów URL w ASP.NET Core
  • Jak zaimplementować ograniczanie szybkości w ASP.NET Core
  • Jak używać usługi Azure Application Insights w ASP.NET Core
  • Korzystanie z zaawansowanych funkcji NLog w ASP.NET Core
  • Jak obsługiwać błędy w ASP.NET Web API
  • Jak zaimplementować globalną obsługę wyjątków w ASP.NET Core MVC
  • Jak obsługiwać wartości null w ASP.NET Core MVC
  • Zaawansowane przechowywanie wersji w ASP.NET Core Web API
  • Jak pracować z usługami roboczymi w ASP.NET Core
  • Jak używać interfejsu API ochrony danych w ASP.NET Core
  • Jak używać warunkowego oprogramowania pośredniczącego w ASP.NET Core
  • Jak pracować ze stanem sesji w ASP.NET Core
  • Jak pisać wydajne kontrolery w ASP.NET Core