Un domain-model con WCF (oggetti DTO e dintorni)
Qualche giorno fa ho proposto sul mio blog l’implementazione di due interfacce diverse da utilizzare con WCF.
La prima implementazione di IFatturazione espone due metodi che ritornano l’XML che rappresentano i tipi:
[ServiceContract()] public interface IFatturazione { [OperationContract] string GetXmlArticolo(string Codice); [OperationContract] string GetXmlCliente(string Codice); }
Il primo GetXmlArticolo prende in input il codice dell’articolo e ritorna l’XML dell’istanza di Articolo ottenuta – in pratica, la serializzazione dell’istanza dell’oggetto. Sul client del servizio WCF, la stringa viene deserializzata per ottenere l’istanza dell’oggetto stesso. In questo caso non ho bisogno di oggetti DTO, perchè l’unica cosa che viaggia avanti ed indietro su WCF sono stringhe, o comunque tipi semplici.
La seconda implementazione di IFatturazione è un po’ più forte dal punto di vista del domain-model. Vediamola:
[ServiceContract()] public interface IFatturazione { [OperationContract] ArticoloDTO GetArticolo(string Codice); [OperationContract] ClienteDTO GetCliente(string Codice); }
Questa interfaccia non passa da XML, ma ritorna direttamente le istanze degli oggetti. Il buon Fabio, autore del libro in allegato ad IoProgrammo, mi ha lasciato un commento che dal punto di vista teorico mi sembra assolutamente incontestabile. Dal punto di vista pratico, invece, ho trovato notevoli perplessità ed un certo complicarsi delle cose. Vi voglio dire dove per arrivare assieme ad una soluzione.
Giustamente, Fabio dice che occorre creare DTO per ogni tipo che voglio utilizzare con WCF. Nel semplice esempio qui sopra, devo creare ArticoloDTO e ClienteDTO. Praticamente, il numero delle classi raddoppia. Non solo: devo decorare ogni classe con l’attributo [DataContract], ed ogni proprietà con l’attributo [DataMember]. Ma questo è il lato semplice della cosa. Sebbene avessi già chiaro il concetto di oggetto DTO, ho preso spunto dai post di Emanuele sul Muro di UGIdotNET, che spiega due metodi diversi (uno e due) su come implementare oggetti DTO.
Nel primo metodo, ed applicandolo al mio semplice caso, la classe ClienteDTO eredita direttamente da Cliente. Sarà la classe ClienteDTO che decorerò con [DataContract]. Peccato però che WCF obbliga anche la classe base ad essere decorata con questo attributo, rendendo di fatto la cosa impossibile se non si dispone del codice sorgente del domain-model. Ma non solo in questo: se volessi mantenere il più possibile il mio domain-model, dovrei evitare di sporcarlo con attributi specifici di una certa particolare tecnologia. Sarà anche una mia fissa, ma il mio domain-model non lo tocco: così l’ho fatto due anni fa, così lo voglio mantenere. Quindi, di fatto realizzare oggetti DTO con l’ereditarietà mi trova contrario.
Nel secondo metodo, la classe ClienteDTO incapsula al suo interno un membro privato di tipo Cliente. Il costruttore di ClienteDTO si preoccupa di prendere in input un’istanza di Cliente con la quale settare il membro privato. Poi, è sufficiente implementare ogni proprietà pubblica che voglio esporre all’esterno. Ancora una volta, la classe DTO deve essere decorata con [DataContract], mentre ogni proprietà con [DataMamber]. Qui è doppiamente scomodo, perchè sono costretto ad implementare una ad una ogni proprietà. Ma la cosa più grave, a mio avviso, è che con l’incapsulamento non posso castare ClienteDTO a Cliente. Quindi, il client di WCF riceve un’istanza di ClienteDTO, che non sa come trasformare in Cliente e di conseguenza, non può più utilizzare in modo naturale il domain-model. Piccola nota: la classe ClienteDTO potrebbe esporre una proprietà pubblica di tipo Cliente, che serva a tirar fuori il membro privato. In questo modo, sarebbe possibile scrivere una linea di codice come questa:
Cliente cl = clienteDTOfromWCF.Cliente;
Cioè, posso ottenere l’istanza di Cliente chiedendola direttamente ad un’istanza di ClienteDTO. Ma anche questa strada non è percorribile, perchè significa decorare con [DataMember] la proprietà pubblica Cliente della classe ClienteDTO. E, di nuovo, torniamo al punto di partenza…cioè…devo mettere mano al sorgente del domain-model, perchè in fase di compilazione mi viene giustamente detto che anche la classe Cliente deve essere decorata con [DataContract].
Stasera finisco qua. Ho appena finito un paio d’ore di sviluppo su WCF, e questo post rappresenta un po’ di punti critici che ho incontrato e che sinceramente non so come risolvere. La prima implementazione di IFatturazione è l’unica che riesco ad utilizzare con produttività, proprio perchè viaggiano solo stringhe, generate dalla serializzazione di oggetti, che subiscono l’operazione inversa lato client.
Technorati Tags: .NET Framework screen WCF