Serializzazione delle Entità dell’ Entity Framework con WCF in NET 3.5 SP1


Un titolo un po' complicato, certo, vediamo di chiarire meglio il contenuto di questo post. Lo scopo è di illustrare con un po' di codice una delle novità della SP1 di .NET 3.5, in particolare il supporto di WCF per la serializzazione delle entità generate dall' Entity Framework, anche quest'ultimo, come forse avete letto, lo trovate ora, insieme al designer installando la SP1. Potete leggere le novità della SP1 qui.


Costruiamo il servizio WCF


Dopo aver installato l'SP1 su una macchina di test, creiamo dunque un progetto di tipo WCF Service Application, come mostrato in figura:


image 


Aggiungiamo ora un nuovo item di tipo ADO.NET Entity Data Model. Due parole sull' Entity Data Model (EDM), per chi non ne ha mai sentito parlare, per gli altri saltate pure il paragrafo. L' EDM  rapprenta il cuore dell ' Entity Framework (EF), consentendovi di "rappresentare" il dominio applicativo della vostra applicazione. L'insieme delle classi che ne scaturiscono non sono necessariamente legate a come è fatto il vostro database in termini di tabelle etc.L' EDM è implementato attraverso un file CSDL, come descritto nella documentazione. Nella sua intimità il designer di VS, che useremo nell'esempio, crea tre file XML: il CSDL descrive appunto le entità con cui la nostra applicazione vuole parlare, ad esempio un cliente ed un ordine, un secondo file SSDL descrive invece come è la struttura relazionale del nostro database, che può non necessariamente mapparsi in modo diretto sulle entità, ad esempio posso avere più tabelle che rappresentano sul db come è fatto un customer. Un terzo e ultimo file MDL descrive invece il mapping tra le entità e le tabelle sul database. Il designer che Visual Studio 2008 ci mette a disposizione crea un file .edmx, che al suo interno è fatto appunto dai tre file XML. Ok, scusate la brevità, ma potete leggere un'introduzione a EF e EDM a questo link.


Nella figura seguente aggiungiamo quindi un nuovo item  e seguendo il wizard proposto utilizzate come database il classico Northwind e per gli scopi di questo post inserite solo le tabelle Customers e Orders.


image 


Il risultato mostrato nel designer dell'EF sarà qualcosa del genere, in cui vedete espressa, una relazione 1-a-molti tra le entità, ad ogni entità corrisponde una classe che poi useremo nell'applicazione. Infatti il designer creerà delle classi, oggetti .NET, che useremo per scrivere il codice e una classe NorthwindEntities che serve a EF e che sarà il nostro entry-point per poter lavorare con EF.


image 


Ora vogliamo esporre un servizio WCF con un semplice metodo che restituisca l'elenco dei client e dei relativi ordini, per fare questo per prima cosa modifichiamo il file IService1 creato in automatico quando abbiamo aggiunto il progetto WCF, come in figura:


image


Nella figura vedete che ho aggiunto il namespace NorthwindModel, che mi è stato creato quando ho usato il designer dell' EF, quindi ho definito nell'interfaccia un unico metodo che restituisce l'elenco di customers, il numero massimo è controllato dal parametro del metodo. Il metodo ha intenzione di restituire l'elenco di clienti e relativi ordini all'applicazione client che invocherà il servizio. Implementiamo ora il servizio  nel file service1.svc.cs usando una query LINQ to Entities. LINQ to Entities è una delle modalità di interrogazione che offre EF, potete anche usare Entity SQL in diversi scenari... questi argomenti sono fuori dallo scopo di questo post.


image


Nell'esempio vedete una semplice query LINQ to Entities, che espone i Customers (al massimo il numero indicato). Nella query notate la clausola Include. Questa viene usata perchè l'EF ha un meccanismo esplicito per il caricamento delle entità, possiamo vedere la query generata su database ad esempio usando il Profiler di SQL Server. Se volete saperne di più sulle strategie di caricamento dell' EF e modalità di interrogazione, leggete questo interessante articolo.


Costruiamo l'applicazione di Test


Bene, ora aggiungiamo una semplice console application e aggiungiamo un riferimento al servizio WCF presente nella solution, come mostrato in figura, in cui stiamo, per l'appunto, aggiungendo una Service Referece all'applicazione  console.


image


 


Ora scriviamo il codice necessario per mostrare l'elenco dei clienti, diciamo i primi due e i relativi ordini


Codice scritto senza la SP1


Quello che succede è che l'applicazione client non vede la classe Orders, poichè questa non è stata serializzata, perdiamo quindi la possibilità di navigare da un generico Customer a tutti i suoi Orders, se non esponendo gli ordini direttamente dal metodo WCF.


Codice scritto con la SP1


Le novità introdotte a WCF nella SP1 supportano la serializzazione del grafo delle entità generate dall'Entity Framework, quindi possiamo scrivere il seguente codice, che ci permette di fare sul client quello che volevamo senza complicare il metodo del servizio WCF.


Ecco il codice, in cui vedete che abbiamo accesso, dato un cliente, anche alla lista degli ordini.


image


Il risultato è quello atteso:


image


Potete scaricare l'esempio di codice a questo link.


Comments (6)
  1. Dall’ ADO.NET Team : i contenuti sono in inglese How Do I Get Started with the Entity Framework? .wmv

  2. Andrea says:

    Ciao Pietro, non ci conosciamo ma leggo sempre con interesse il tuo blog.

    Che soluzioni abbiamo in uno scenario multi tiered application a componenti (nel senso che espongo interfacce e datatype) per esporre le entità al presentation layer? Dobbiamo passare da un servizio WCF? Dobbiamo fare un nuovo remap adhoc tra i nostri datatype esposti e le entità dell’ef? O c’è qualche altra invenzione che mi sfugge? Grazie.

  3. PietroBr says:

    Ciao Andrea,

    Domanda e risposta complessa, ma provo a sintetizzare. Con EF puoi partire a creare un tuo Domain Model e poi mapparlo su tuo DBMS negli scenari e provider previsti. Quindi puoi usare le classi generate con WCF in scenari multi-tier/layer.

  4. Vincenzo says:

    Ciao Pietro,

    facendo dei test di performance, mi sono imbattuto nel seguente caso.

    Il codice e’ simile al tuo esempio, solo che per migliorare le performance lato server ho provato a mantenere in cache il context in modo da lasciare i customer attached al context.

    Il test e’ il seguente:

    ho due metodi WCF uno che ritorna la lista delle chiavi di tutti i Customer ed un altro metodo che ritorna tutte le infomazioni dei customer (l’intero entityObject) avendo come parametro la chiave.

    Senza cache il context, ovvero aprendo un context (utilizzando lo using) ad ogni chiamata WCF impiego un tempo t.

    Mantenendo in cache il context lato server impiego un tempo 10*t !

    Una possibile spiegazione che trovo e’ che quando invio il customer nel servizio wcf l’objectEntity viene serializzato e questo crea problemi al context, nella gestione dei suoi attached objects , tu cosa ne pensi?

    Grazie,

    Vincenzo

  5. PietroBr says:

    Ciao Vincenzo, ci sono almeno 3 ragioni per non usare una cache: la prima è che l’objectcontext è già in cache a livello di appDomain, vedi il post che ho fatto sulle performance di EF; la seconda è che usare una cache con un oggeto di questo tipo può limitare la scalabilità in scenari multi-server; la terza è che comunque l’apertura/chiusura delle connessioni al server è già pensata per usare l’objectcontext come mostrato dagli esempi.

  6. Massimo says:

    Ciao Pietro, ho un problema con il savataggio del datasevicecontext. Quando tento di aggiungere al database un oggetto contenente una proprietà di tipo byte[] alla quale asegno un file pdf serializzato.

    if (ofd.ShowDialog() == DialogResult.OK)

    {

    FileInfo fi = new FileInfo(ofd.FileName);

    int size = (int)fi.Length;

    byte[] bufferLettura =  new byte[size];

    FileStream sr = File.OpenRead(ofd.FileName);

    sr.Read(bufferLettura, 0, size);

    sr.Close();

    this.DataSource.Oggetto = bufferLettura;

    this.DataSource.NomeFile = Path.GetFileName(ofd.FileName);

    this.DataSource.DataOra = DateTime.Now;

    }

    SUL SAVATAGGIO DEL CONTESTO OTTENGO

    Errore HTTP 400.0 – Bad Request

Comments are closed.

Skip to main content