[[File:DotNet3.0.svg|thumb|upright=1.4|Questo ''sottosistema'' è parte della piattaforma [[.NET Framework 3.0]]]]
{{W|informatica|ottobre 2007}}
'''Windows Communication Foundation''' (WCF), conosciuto in fase di sviluppo con il nome in codice '''Indigo''', è un "sottosistema applicativo" proprietario della [[Microsoft]], che offre la struttura [[Application programming interface|API]] per la creazione di applicazioni distribuite in ambienti [[Windows]].
{{S!informatica}}
Se da un lato ogni [[protocollo di rete]] (e.g. [[Hypertext Transfer Protocol|HTTP]], [[File Transfer Protocol|FTP]], [[Simple Mail Transfer Protocol|SMTP]], ecc.) ha un suo modello di programmazione, e necessita quindi di una conoscenza specifica da parte degli sviluppatori per poter essere utilizzata, WCF è stato realizzato con l'intento di ricondurre ad un unico modello diverse tecnologie, rendendo più semplice ed uniforme la programmazione in ambiente Windows.
È stato sviluppato per [[Windows Vista]], ma è disponibile anche per i sistemi [[Windows XP#Service Pack 2|Windows XP SP2]], [[Windows Server 2003]] e [[Windows 7]].
== Definizione del sottosistema ==
'''Windows Communication Foundation''' (WCF) è un ''[[layer applicativo]]'' proprietario della [[Microsoft]], che offre la struttura per la creazione di applicazioni distribuite in ambienti [[Windows]].
Un servizio WCF si basa sugli '"EndPoint", che sono le porte attraverso le quali le applicazioni comunicano con il mondo esterno; si può quindi affermare che un servizio WCF sia una collezione di EndPoint. A sua volta, un Endpoint è costituito da quelli che sono i pilastri di WCF: "'''Address'''", "'''Binding'''", "'''Contract'''".
Attualmente esistono diverse tecnologie per creare questo tipo di applicazioni e tutte ottimamente supportate dal .NET framework. Si ricorre ai WebService quando si ha l'esigenza di interoperabilità con il maggior numero di sistemi eterogenei e di Remoting, nel caso in cui si devono mettere in comunicazione due sistemi .NET ed avere un forte controllo su entrambi, e, ancora, Microsoft Message Queue (MSMQ) per sviluppare applicazioni asincrone basate su messaggi. Visto il supporto già esistente per ogni tipo di esigenza, ci si può chiedere quale sia stato il motivo che ha spinto Microsoft a creare un nuovo Framework per applicazioni distribuite; la risposta è più semplice di quanto si possa immaginare. Ogni tecnologia ha un suo modello di programmazione e necessita quindi di una conoscenza specifica, da parte degli sviluppatori, per poter essere utilizzata.
WCF pone fine a questa Babele unificando in un unico modello di programmazione tutte le attuali tecnologie. Infatti, in WCF, il codice da sviluppare diventa unico qualunque sia la modalità di trasporto delle informazioni (HTTP, HTTPS, TCP, ecc).
=== Cos'è l'Address ===
Si parte dall'ABC
L'Address è l'indirizzo al quale il servizio risponde. L'indirizzo è composto da un [[Uniform Resource Identifier|URI]], una "Identity" ed una lista di "Header". In fase di definizione di un Address, l'informazione principale è l'URI, che corrisponde all'indirizzo fisico del servizio. Header e Identity sono informazioni che invece sono necessarie solo in casi particolari. Ad esempio quando ci sono più EndPoint, può essere utile avere diversi Header a seconda dell'Endpoint che il client utilizza. In parole semplici si può definire l'address come il DOVE.
Un servizio WCF si basa sugli EndPoint che sono le porte attraverso le quali l'applicazione comunica con il mondo esterno; si può quindi affermare che un servizio WCF sia una collezione di EndPoint. A sua volta, un Endpoint è costituito da quelli che sono i pilastri di WCF: Address, Binding, Contract.
Cos’è l’address
L'Address è l'indirizzo al quale il servizio risponde. L'indirizzo è composto da un Uri, un Identity e una lista di Headers. In fase di definizione di un Address, l'informazione principale è l'URI che corrisponde all'indirizzo fisico del servizio (es. http://localhost/ws/svc). Headers e Identity sono informazioni che invece sono necessarie solo in casi particolari. Ad esempio quando ci sono più EndPoint può essere utile avere diversi Headers a seconda dell'Endpoint che il client utilizza. In parole semplici si può definire l'address come il DOVE.
Cos’è il binding
Gran parte della magia dietro WCF sta nei Bindings. Infatti se ci si può occupare del codice senza preoccuparsi dell'infrastruttura di trasporto lo si deve soprattutto a questa feature. I Bindings si occupano di quello che avviene tra il momento in cui il servizio spedisce logicamente il messaggio ed il momento in cui viene fisicamente messo in rete. In questo lasso di tempo vengono eseguiti numerosi passi che seguono una precisa pipeline di cui i bindings sono responsabili.
Durante l'esecuzione della pipeline il messaggio deve attraversare due layer: il primo si occupa dei Behaviours, ovvero delle trasformazioni che deve subire un messaggio, il secondo si occupa dei Channels ovvero dell'instradamento verso il canale fisico di trasporto. Nel primo layer ci si occupa della conversione dei dati dal formato 'codice' al formato messaggio; ad esempio, vengono trasformate le informazioni da una classe al formato xml di un messaggio SOAP. In aggiunta i Behaviours si occupano anche della sicurezza, del criptaggio delle informazioni e di tutte le feature relative ai dati. Durante la seconda fase il messaggio viene messo sul canale di trasporto secondo quanto specificato in fase di configurazione. Quindi è in questa fase che si istanzia il canale (HTTP, HTTPS, MSMQ, TCP) su cui viaggeranno le informazioni. Poiché a livello di protocollo si possono controllare alcuni dettagli, in questo layer si possono aggiungere informazioni sulla modalità di trasmissione, protetta o meno, oppure sul Reliable Messaging. Come detto in precedenza, questo processo avviene attraversando una pipeline.
Seguendo lo stesso concetto della pipeline di asp.net, possiamo vedere tutte le opzioni dette finora (protocollo, formattazione, ecc) come moduli da inserire nel flusso di elaborazione del messaggio.
Poiché la gestione dei Bindings può essere interamente gestita in fase di configurazione, si può intuire come semplicemente cambiando poche voci nel config si può passare dalla pubblicazione in modalità WebService su HTTPS criptato con un certificato digitale, ad un formato su TCP con ReliableMessaging senza dover intaccare il codice. Se si volesse dare una parola chiave ai bindings questa sarebbe COME.
Cosa sono i Contracts
Dopo l'A e la B è il momento della C dei Contracts. I Contracts rappresentano l'interfaccia software, ovvero le API, che il nostro servizio pubblica. Poiché esistono diversi tipi di contratti e l'argomento è molto vasto è giusto creare una sezione a parte. Si può comunque dire che i Contracts siano il COSA.
WCF è stato pensato sin dall'inizio tenendo in mente le architetture orientate ai servizi. In una tecnologia come questa è molto importante mettere a disposizione un'interfaccia software che l'utilizzatore del servizio ed il servizio possono utilizzare per comunicare. In WCF quest'interfaccia di scambio è il contratto.
I contratti non stabiliscono solo quali operazioni si possono invocare su un servizio, ma anche come e quali dati si debbano scambiare. Da questa considerazione si evince che esistono diverse tipologie di contratti racchiuse in tre tipologie: ServiceContract, DataContract e MessageContract.
=== Cos'è il Binding ===
I ServiceContract definiscono il servizio e tutte le API che mette a disposizione. La definizione di un simile contratto vede la sua naturale definizione in un'interfaccia .NET da implementare. Di per se, un'interfaccia non ha alcun senso parlando in termini di Service Oriented Architecture, infatti, pur definendo metodi e proprietà, non stabilisce se questi debbano essere resi pubblici o meno. Bisogna ricordare che in con SOA la visibilità di un metodo o di una proprietà all'interno di una classe, non ha alcun collegamento con la visibilità che può avere all'interno del servizio. A seconda dei casi, un metodo privato di una classe potrebbe diventare un'API del servizio, mentre un metodo pubblico della stessa classe potrebbe non essere pubblicato dal servizio. In WCF, per definire i metodi da pubblicare, bisogna decorarli con opportuni attributi dichiarati nella definizione dell'interfaccia. Gli attributi da utilizzare sono ServiceContract con la quale marcare l'interfaccia e OperationContract per ogni metodo da pubblicare.
Gran parte della soluzione proposta da WCF sta nel concetto di Binding. Infatti se ci si può occupare del codice senza preoccuparsi dell'infrastruttura di trasporto lo si deve soprattutto a questa ''feature''. I Binding si occupano di quello che avviene tra il momento in cui il servizio spedisce logicamente il messaggio ed il momento in cui viene fisicamente trasmesso in rete. In questo lasso di tempo vengono eseguiti numerosi passi che seguono una precisa ''[[pipeline dati|pipeline]]'' di cui i binding sono responsabili.
Una volta che è stato stabilito quali operazioni mettere a disposizione dei client, arriva il momento di definire quali informazioni debbano essere pubblicate. Questo è compito dei DataContract. Supponiamo che un servizio pubblichi un metodo che dato il codice fiscale ritorni i dati della persona associata. Nel DomainModel l'oggetto Persona contiene informazioni come Nome, Cognome, Data di Nascita e altro ancora, tuttavia può nascere l'esigenza di non pubblicare tutti i dati della persona ma soltanto quelli che si ritengono opportuni. Per ottenere un risultato del genere bisogna decorare sia la classe che le sue proprietà con attributi, più approfonditamente alla classe va applicato l'attributo DataContract e alle proprietà l'attributo DataMember.
Durante l'esecuzione della pipeline il messaggio deve attraversare due livelli: il primo si occupa dei ''[[Comportamento|Behaviour]]'' (comportamenti), ovvero delle trasformazioni che deve subire un messaggio, il secondo si occupa dei Canali (detti ''Channel''), ovvero dell'instradamento verso il canale fisico di trasporto. Nel primo livello ci si occupa della conversione dei dati dal formato 'codice' al formato messaggio; ad esempio, vengono trasformate le informazioni da una classe al formato [[XML]] di un messaggio [[SOAP]]. In aggiunta i Behaviour si occupano anche della sicurezza, della criptazione delle informazioni e di tutte le funzioni di gestione del dato. Durante la seconda fase il messaggio viene messo sul canale di trasporto secondo quanto specificato in fase di configurazione. Quindi è in questa fase che si instanzia il canale del protocollo originale su cui viaggeranno le informazioni. Poiché a livello di protocollo si possono controllare alcuni dettagli, in questo livello si possono aggiungere informazioni sulla modalità di trasmissione, protetta o meno, oppure sul Reliable Messaging. Come detto in precedenza; questo processo avviene per mezzo di una pipeline.
Per default, tutte le proprietà di una classe vengono mappate all'interno del corpo di un messaggio. A seconda delle esigenze, può capitare che si debbano piazzare delle informazioni nelle intestazioni invece che nel corpo; questo mapping tra le classi ed il formato del messaggio viene impostato tramite MessageContract. Anche in questo caso l'impostazione di queste opzioni avviene tramite attributi e, più precisamente, MessageContract per la classe e MessageBody o MessageHeader per le proprietà.
Seguendo lo stesso concetto della pipeline di [[ASP.NET]], possiamo vedere tutte le opzioni finora illustrate (protocollo, formattazione, ecc.) come moduli da inserire nel flusso di elaborazione del messaggio.
Un'occhiata al codice
Poiché la gestione dei Binding può essere interamente gestita in fase di configurazione, si può intuire come semplicemente cambiando poche voci si può passare dalla pubblicazione in modalità [[Web]] su [[HTTPS]] criptato con un [[certificato digitale]], ad un trasporto diverso del messaggio come SMTPS (''SMTP Secured'') senza dover modificare il codice. Se si volesse dare una parola chiave ai binding questa sarebbe COME.
Dopo tanta teoria, è arrivato il momento di passare al codice. Come esempio verrà creato un servizio che riceve in input un codice prodotto e restituisce tutte le informazioni legate al prodotto con quel codice.
La prima cosa da fare quando si costruisce un servizio con WCF è stabilire il contratto di comunicazione tramite interfaccia che nel nostro caso è la seguente:
[ServiceContract]
public interface IContract {
[OperationContract]
Product GetProductById(string IdProduct);
}
=== Cosa sono i Contract ===
Come detto in precedenza, è importante notare l'uso degli attributi.
I ''Contract'' (o contratti) rappresentano l'[[interfaccia (informatica)|interfaccia]] [[software]] vera e propria, ovvero le API, che il servizio pubblica. Poiché ne esistono diverse tipologie l'argomento è molto vasto, si rimanda alla sezione collegamenti esterni della voce chi volesse approfondire l'argomento. Si può comunque dire che i Contract rappresentano il COSA.
== Architettura ==
Una volta stabilito quali servizi mettere a disposizione, si determina quali dati l'entità Product debba pubblicare e quali invece debba mantenere privati:
WCF è stato pensato sin dall'inizio tenendo in mente le architetture orientate ai servizi. In una tecnologia come questa è molto importante mettere a disposizione un'interfaccia software che l'utilizzatore del servizio ed il servizio stesso possano utilizzare per comunicare. In WCF quest'interfaccia di scambio è il ''Contract'' (ovvero ''contratti'').
[DataContract]
I contratti non stabiliscono solo quali operazioni si possono invocare su un servizio, ma anche come e quali dati si debbano scambiare. Da questa considerazione si evince che esistono diverse tipologie di contratti racchiuse in tre tipologie: '''''ServiceContract''''', '''''DataContract''''' e '''''MessageContract'''''.
public class Product{
=== I ServiceContract ===
[DataMember]
I ServiceContract definiscono il servizio e tutte le API che questi mette a disposizione. La definizione di un simile contratto vede la sua naturale implementazione in un'interfaccia .NET da sviluppare. Di per sé, un'interfaccia non ha alcun senso parlando in termini di ''[[Service-oriented architecture]]'' (SOA); infatti, pur definendo metodi e proprietà, non stabilisce se questi debbano essere resi pubblici o meno. Bisogna ricordare che con SOA la visibilità di un metodo o di una proprietà all'interno di una classe non ha alcun collegamento con la visibilità che può avere all'interno del servizio. A seconda dei casi, un metodo privato di una classe potrebbe diventare un'API del servizio, mentre un metodo pubblico della stessa classe potrebbe non essere pubblicato dal servizio. In WCF, per definire i metodi da pubblicare, bisogna arricchirli con opportuni attributi dichiarati nella definizione dell'interfaccia. Gli attributi da utilizzare sono ServiceContract con la quale marcare l'interfaccia e '''''OperationContract''''', per ogni metodo da pubblicare..
public string IdProduct{
get { return _idProduct; }
set { _idProduct = value; }v }
[DataMember]
public string Name{
get { return _name; }
set { _name = value; }
}
[DataMember]
private decimal Price{
get { return _price; }
set { _price = value; }
}
public string Category{
get { return _category; }
set { _category = value; }
}
}
=== I DataContract ===
Qui la cosa principale su cui porre attenzione è la possibilità di pubblicare la proprietà Price nonostante questa sia privata. Infatti, quando il client riceverà le informazioni i dati dell'entità Product saranno tre: IdProduct, Name e Price e non Category nonostante sia pubblico. Poiché gli attributi vengono utilizzati dal runtime di WCF per serializzare i dati, questi sono il naturale contenitore di alcune proprietà che permettono di controllare questo processo. Infatti possiamo definire come chiamare l'elemento che contiene la classe o come chiamare i singoli attributi che espongono i valori delle proprietà.
Una volta che è stato stabilito quali operazioni mettere a disposizione dei [[client]], arriva il momento di definire quali informazioni debbano essere pubblicate. Questo è compito dei DataContract. Supponiamo che un servizio pubblichi un metodo che dato il [[codice fiscale]] ritorni i dati della persona associata. Nel '''''DomainModel''''' l'oggetto Persona contiene informazioni come Nome, Cognome, Data di Nascita e altro ancora, tuttavia può nascere l'esigenza di non pubblicare tutti i dati della persona ma soltanto quelli che si ritengono opportuni. Per ottenere un risultato del genere bisogna corredare sia la classe che le sue proprietà con attributi, più precisamente alla classe va applicato l'attributo DataContract e alle proprietà l'attributo '''''DataMember'''''.
Possono essere definite anche altre proprietà come l'ordine, l'obbligatorietà di un dato e altro ancora.
=== I MessageContract ===
Nonostante questo buon livello di controllo a volte si ha bisogno di un controllo totale sul processo di serializzazione, in questo caso la cosa migliore è marcare l'interfaccia con l'attributo XmlSerializerFormat che invece di sfruttare il serializzatore di default utilizza il serializer standard del .NET Framework che viene utilizzato anche per i WebService Asmx.
Per ''[[default (informatica)|default]]'', tutte le proprietà di una classe vengono mappate all'interno del corpo di un messaggio. A seconda delle esigenze, può capitare che si debbano piazzare delle informazioni nelle intestazioni invece che nel corpo; questa mappatura tra le classi ed il formato del messaggio viene impostato tramite i MessageContract. Anche in questo caso l'impostazione di queste opzioni avviene tramite attributi e, più precisamente, MessageContract per la classe e '''''MessageBody''''' o '''''MessageHeader''''' per le proprietà.
A questo punto l'interfaccia è pronta, le classi sono stabilite, manca solo l'implementazione del codice per restituire i dati:
public class ProductRetriever : IContract {
public Product GetProductById(string IdProduct){
Product p = new Product();
p.IdProduct = 1;
p.Name = 'name';
p.Category = 'category';
return p;
}
}
== Voci correlate ==
La parte relativa al codice è finita. Per realizzare un servizio WCF questo è tutto il codice di cui abbiamo bisogno. Come si vede, non c'è alcun riferimento al tipo di tecnologia di trasmissione dati o codice di serializzazione o altro ancora.
* [[Windows Vista]]
Hosting del servizio
* [[.NET Framework 3.0]]
Un servizio WCF non è una vera applicazione, quindi ha bisogno di appoggiarsi ad una struttura che ne permetta la pubblicazione; in pratica il servizio ha bisogno di un Host. Si possono utilizzare diversi tipi di Host: ad esempio possiamo scrivere una Console Application, un Servizio Windows o, più semplicemente, utilizzare IIS. Quando si vuole utilizzare una propria applicazione per ospitare un servizio, occorre scrivere del codice per preparare l'infrastruttura necessaria, quindi istanziare le classi che si occupano della gestione dell'endpoint.
* [[ASP .NET]]
Come già accennato, la magia di WCF sta in parte nel codice semplificato ed unificato per ogni modalità di comunicazione, e in parte nel fatto che semplicemente cambiando la configurazione si può passare da http a TCP, da messaggi in chiaro a messaggi criptati, ecc ecc. In realtà tutto quello che si può configurare da file può essere realizzato anche da codice, ma non è buona pratica cablare nell'applicazione queste informazioni. Può essere invece molto utile realizzare una form di gestione della configurazione al fine di rendere la modifica più semplice in fase di deploy.
Il posto naturale dove inserire le informazioni di configurazione è il file .config all'interno del quale va inserito un nodo system.serviceModel che è il contenitore di ogni impostazione:
<configuration>
<system.serviceModel>
<services>
<service name="WinFXItalia.Library.ProductRetriever">
<endpoint
address="http://localhost/ws/svc"
binding="basicHttpBinding"
contract="WinFXItalia.Library.IContract" />
</service>
</services>
</system.serviceModel>
</configuration>
Dal file di configurazione possiamo ricavare tutte le informazioni necessarie per il funzionamento del servizio e utilizzarle da codice per istanziare il servizio utilizzando l'oggetto ServiceHost in una semplice console application:
using (ServiceHost serviceHost = new ServiceHost(typeof(WinFXItalia.Library.ProductRetriever), "http://localhost/ws/svc")) {
serviceHost.Open();
}
Una volta avviata l'applicazione questa resterà in ascolto in base alle informazioni specificate nel .config relative all'address, binding e contract.
Nel caso del nostro servizio, la creazione manuale di un Host è alquanto inutile in quanto possiamo sfruttare IIS. Con l'installazione di WCF viene inserito un nuovo mapping nel metabase di IIS che associa l'estensione .SVC alla pipeline di asp.net. Grazie a questa estensione, il runtime capisce che quando arriva una richiesta con estensione SVC questa deve essere passata al motore di WCF che istanzia il servizio per soddisfare la richiesta.
La tecnica è molto simile ai file .asmx e consiste nel creare un file .svc contenente la dichiarazione del servizio da utilizzare:
<%@ServiceHost language="c#" Debug="true" Service="WinFXItalia.Library.ProductRetriever" %>
Sfruttare il servizio: il Client
Quando si parla di servizi, ci sono sempre due entità: una è il servizio che, una volta avviato, rimane in attesa di essere invocato; l'altra è il client che invia messaggi al servizio.
Il client può essere una qualsiasi applicazione, sia essa WinForm, Web, un secondo servizio WCF o ovviamente una qualsiasi altra piattaforma. Per poter invocare un servizio, il client deve conoscere l'interfaccia di comunicazione che in WCF è il contratto, quindi, analogamente a quanto avviene ora per i WebService, è necessario creare un proxy che si interfacci al servizio.
Attualmente, Visual Studio non ha un'interfaccia grafica per costruire in automatico il proxy, quindi la sola possibilità è utilizzare il tool SvcUtil.exe da riga di comando. Questo tool risulta molto comodo perché non solo crea automaticamente il proxy, ma anche il file di configurazione che il client può utilizzare per la connessione. Quest'ultima frase lascia capire che anche il client può essere pilotato da configurazione senza bisogno di codice esattamente come si fa con il servizio.
Avendo anche il client un EndPoint, le informazioni da pubblicare sono le stesse del servizio: l'Address, il Binding ed il Contract. I primi due corrispondono ai dati dell'endpoint utilizzato dal servizio, mentre il contract corrisponde alla classe automaticamente generata nel proxy. L'altra differenza rispetto alla configurazione del servizio è il nome del nodo principale che contiene i dati: invece di avere un nodo <services> con diversi <service> innestati, esiste un nodo client con tutti gli endpoint figli:
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://localhost/ws/svc"
binding="basicHttpBinding"
contract="WinFXItalia.Library.IContract"/>
</client>
</system.serviceModel>
</configuration>
Anche qui, una volta stabilita l'interfaccia si passa al codice per invocare il servizio e ricevere i dati. Nel nostro caso il client sarà una classica Windows Application che al click di un bottone invoca il servizio.
using (ContractProxy proxy = new ContractProxy()) {
WinFXItalia.Library.Product p = proxy.GetProductById("1");
}
Questo snippet illustra come il codice sia in realtà molto banale e simile a quello che si fa ora per i WebService: si crea un'istanza del proxy e si invoca il metodo. Anche per il client, qualunque sia il protocollo, i Behaviours e altro ancora, sarà sempre compito di WCF eseguire la pipeline che porta alle trasformazioni e all'invio fisico del messaggio e viceversa alla ricezione della risposta, ripercorrendo la pipeline al contrario.
È stato sviluppato per Windows Vista, ma è disponibile anche per i sistemi [[Windows XP]] SP2 e [[Windows Server 2003]].
== Collegamenti esterni ==
*[http {{cita web|https://msdn.microsoft.com/Longhorn/understanding/pillarsit-it/Indigolibrary/defaultms731067.aspx|Programmazione MicrosoftWCF Developerdi Network]base}}
* {{cita web|http://msdn2.microsoft.com/it-it/library/ms735119(en-us,VS.85).aspx|Microsoft Developer Network|lingua=en}}
*[http://www.aspitalia.com/articoli/longhorn/windows_longhorn.aspx Panoramica generale sulle nuove tecnologia di Windows Longhorn]
{{portale|Microsoft}}
[[Categoria:Microsoft Windows]]
[[de:Windows Communication Foundation]]
[[en:Windows Communication Foundation]]
[[es:Windows Communication Foundation]]
[[fi:Windows Communication Foundation]]
[[fr:Windows Communication Foundation]]
[[ja:Windows Communication Foundation]]
[[nl:Windows Communication Foundation]]
[[pl:Windows Communication Foundation]]
[[ru:Windows Communication Foundation]]
[[sv:Windows Communication Foundation]]
[[tr:Windows Communication Foundation]]
|