Nel precedente script abbiamo visto come l'utilizzo di una entità di Entity Framework possa portare a problemi nella serializzazione JSON a causa delle referenze circolari. L'esempio citato, però, è solo la punta dell'iceberg di una serie di problematiche che sorgono nel momento in cui esponiamo direttamente a utilizzatori esterni le entità di dominio.
Il modo corretto di procedere in queste casistiche, infatti, è quello di esporre il dato sotto forma di DTO (Data Transfer Object), ossia oggetti creati appositamente per essere condivisi verso l'esterno, magari con una strutturazione differente rispetto alle entità. I benefici sono molteplici:
- Se il dominio dovesse variare, i DTO assicurano che il messaggio scambiato con l'esterno rimanga invece il medesimo;
- tipicamente i modelli di dominio hanno una sovrastrutturazione rispetto a quanto è necessario comunicare all'esterno: per esempio, per un ordine può essere sufficiente una proprietà stringa con il nome del cliente, piuttosto che una reference verso una entità cliente;
- le entità di dominio possono avere dei dati che non vogliamo esporre all'esterno, quali identificativi, campi di servizio, informazioni riservate.
Consideriamo l'esempio di un ordine:
public class Order { public int Id { get; set; } public DateTime Date { get; set; } public Customer Customer { get; set; } ... }
Un data transfer object corrispondente potrebbe avere la seguente forma:
public class OrderDto { public DateTime Date { get; set; } public string Customer { get; set; } ... }
Gestire oggetti di questo tipo, però, può risultare molto tedioso, perché ci troviamo spesso a fare assegnazioni di proprietà tra l'una e l'altra tipologia di ordine. Proprio per evitare tutto questo codice boiler plate, possiamo utilizzare un tool, denominato Automapper, che è disponibile gratuitamente su NuGet.
Grazie ad Automapper, infatti, possiamo creare un mapping tra Order e OrderDto in modo che le assegnazioni vengano effettuate in maniera del tutto automatica. Allo startup dell'applicazione, non dobbiamo far altro che scrivere questo codice:
protected void Application_Start() { // ... Mapper.CreateMap<Order, OrderDto>() .ForMember(x => x.Customer, x => x.MapFrom(y => y.Customer.Name)); Mapper.AssertConfigurationIsValid(); }
La logica di funzionamento che regola la conversione è molto semplice: dove non specificato diversamente, tutte le proprietà dell'oggetto di destinazione (in questo caso OrderDto) vengono recuperate dalle proprietà omonime dell'oggetto origine (e quindi Order). Ovviamente questa regola non è sempre applicabile, e per questa ragione Automapper consente di specificare una serie di direttive. Per esempio, nel codice in alto, stiamo mappando la proprietà OrderDto.Customer, di tipo stringa, con la proprietà Name di Order.Customer.
La chiamata ad AssertConfigurationIsValid va poi effettuata a valle della configurazione, per verificare che tutte le impostazioni siano corrette.
Ciò che è importante, è che con i DTO abbiamo assoluto controllo di ciò che, per esempio, esponiamo all'esterno nella forma di un oggetto serializzato in formato JSON:
public ActionResult JsonDemo(int id) { var order = OrderRepository.Get(id); var model = Mapper.Map<OrderDto>(order); return this.Json(order, JsonRequestBehavior.AllowGet); }
Automapper è molto flessibile e presenta diverse opzioni di personalizzazione, per le quali rimandiamo alla guida ufficiale:
https://github.com/AutoMapper/AutoMapper/wiki
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Paginare i risultati con QuickGrid in Blazor
Registrare servizi multipli tramite chiavi in ASP.NET Core 8
Generare token per autenicarsi sulle API di GitHub
Applicare il versioning ai nostri endpoint ASP.NET Core Minimal API
Semplificare il deployment di siti statici con Azure Static Web App
Personalizzare l'errore del rate limiting middleware in ASP.NET Core
Utilizzare HiLo per ottimizzare le insert in un database con Entity Framework
Determinare lo stato di un pod in Kubernetes
Gestire errori funzionali tramite exception in ASP.NET Core Web API
Eseguire operazioni con timeout in React
Implementare il throttling in ASP.NET Core
Utilizzare politiche di resiliency con Azure Container App
I più letti di oggi
- Vuoi incontrare Bill Gates? Viaggia con ASPItalia.com!
- Customizzare il pager del DataGrid
- Stabilire un collegamento VPN tra una Web App e una Virtual Network
- Documentare ASP.NET Web API con Swagger
- Usare i servizi REST di BING per ottenere informazioni sulla posizione dell'utente
- Visual Studio 2005 CTP May