Perché WCF (Windows Communication Foundation) ?
Il mondo del software si sta muovendo sempre più costantemente verso le applicazioni distribuite ed orientate ai servizi (
SOA), ma noi sviluppatori, per poter trovare la soluzione migliore alle specifiche di progetto, dobbiamo destreggiarci tra diverse tecnologie:
Web Services, Remoting, Message Queue, ecc. La soluzione? Creare un Framework che possa unificare tutte queste tecnologie in modo da renderci la vita facile, il
WCF.
Cosa è necessario per iniziare a programmare WCF ?
Oltre a una buona dose di pazienza e del tempo da investire si può utilizzare come IDE sia
Visual Studio .NET 2005 sia
Visual Studio .NET 2008. Per il 2005 è necessario installare sul sistema operativo il
Windows SDK (
Download Windows SDK ), il
2008 invece è già pronto per lo sviluppo con
WCF. C'è disponibile al pubblico una
Beta 2 di
Visual Studio .NET 2008, il link lo trovate più avanti nell'articolo.Il mio consiglio personale è di usare come combinazione
VS.NET 2008 su Windows Vista per programmare
WCF.
Ok ! Ma come funziona?
Il
WCF è molto più semplice di quanto si possa pensare, si basa su tre componenti fondamentali:
1) COSA voglio comunicare
(Contract);
2) COME la voglio comunicare
(Binding);
3) DOVE voglio che sia accessibile
(Address).
Cosa voglio comunicare – Contract
Nel
Contract vengono definiti i metodi e le proprietà che fanno parte del nostro servizio. Per descriverne la struttura è necessario dichiarare una interfaccia che, come un vero contratto, dovrà indicare quali informazioni e quali operazioni saranno rese accessibili ai client che interrogheranno il servizio utilizzando degli attributi, nello specifico:
?
OperationContract: Metodi del servizio utilizzabili dai client.
?
DataContract: Strutture dati (classi, enum e struct).
?
DataMember: Proprietà pubbliche del servizio.
Questo ci dà la massima libertà nella programmazione, infatti gli elementi che il servizio offrirà non saranno necessariamente elementi pubblici della classe, separando i modificatori di accesso dei nostri oggetti da quelli del servizio; in parole povere un metodo
private può benissimo essere indicato come un
OperationContract.
Come voglio comunicare – Binding
Il
Binding è la vera punta di diamante del
WCF, infatti si preoccupa di trasformare e trasmettere le nostre informazioni nel protocollo da noi prescelto:
http, https, tcp, ecc. In questo modo possiamo sviluppare il nostro servizio senza preoccuparci del modo in cui comunicherà. Il
Binding inoltre ha il compito di salvaguardare la sicurezza del messaggio, dichiarando dei
Behaviour per la trasformazione delle nostre informazioni in formato sicuro.
Dove voglio che sia accessibile – Address
L’
Address è l’indirizzo a cui il mio servizio è interrogabile, semplice no ?!
Questi tre elementi costituiscono quello che viene definito un
Endpoint, e per ogni servizio possiamo definirne anche più di uno, per rendere la nostra applicazione compatibile con quelle già presenti e non limitare la comunicazione ad un singolo protocollo.
Il mio primo servizio WCF
Proviamo a costruire il nostro primo servizio
WCF con le poche nozioni di teoria che abbiamo, e che verranno ampliate negli articoli successivi. In questo articolo utilizzerò la
Beta di Visual Studio .NET 2008, scaricabile gratuitamente da questo indirizzo:
Visual Studio 2008 Standard Download Apriamo il nostro IDE e creiamo un nuovo progetto
WCF.
Analizzando il progetto notiamo subito i componenti del
WCF. Per primo bisogna avere un'interfaccia con attributo
[ServiceContract]:
[ServiceContract]
public interface IService1
{
...
[OperationContract]
string GetData(int intParam);
...
}
Come si può notare all'interno dell'interfaccia sono presenti dei metodi indicati come
[OperationContract], i metodi che potranno essere eseguiti dai client. Inoltre, all'interno dello stesso file, viene inclusa una struttura dati con attributo
[DataContract] e con proprietà
[DataMember]:
[DataContract]
public class CompositeType
{
...
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
...
}
Definito il Contract è necessario definire la classe che implementi la nostra interfaccia:
public class Service1 : IService1
{
...
}
Ora manca da definire gli altri due componenti fondamentali del WCF,
l'Address e il Binding. Entrambi sono definiti all'interno dell'
App.Config:
Address<host>
<baseAddresses>
<add baseAddress = "http://localhost:8080/Service1" />
</baseAddresses>
</host>
Binding<endpoint address ="" binding="wsHttpBinding" contract="WcfServiceLibrary1.IService1" />
Per quanto riguarda il binding c'è da sottolineare il fatto che è possibile definire anche più di un Endpoint, indicando diversi contract e diversi tipi di Binding, di seguito un elenco di quelli possibili:
BasicHttpBinding (Comunicazione)
WSHttpBinding (Binding per la comunicazione sicura, adatta per comunicazioni non duplex)
WSDualHttpBinding (Binding per la comunicazione sicura, adatta per comunicazioni duplex tamite protocollo SOAP)
WSFederationHttpBinding (Binding che supporta il protocollo WS-Federation)
NetTcpBinding (Comunicazione TCP/IP adatta per applicazioni cross-machine)
NetNamedPipeBinding (Comunicazione basata su Named Pipe)
NetMsmqBinding (Binding che utilizza il protocollo message queue su una singola macchina)
NetPeerTcpBinding (Protocollo per la comunicazione multi macchina)
MsmqIntegrationBinding (Binding che utilizza il protocollo message queue cross-machine)
All'interno del nostro
App.config viene definito anche un
Behavior che permetterà l'interrogazione via http del servizio, in questo modo quando andremo a creare il nostro client, potremo aggiungere una
Service Reference ed ereditare automaticamente i metodi del servizio.
<serviceMetadata httpGetEnabled="True"/>
A questo punto possiamo vedere il nostro servizio funzionare semplicemente eseguendolo in debug, e appararirà una finestra con l'elenco dei servizi attivi (in questo caso solo uno):
Inoltre possiamo anche visualizzare il
WSDL tramite
Internet Explorer, indicando l'url
http://localhost:8080/Service1?wsdl, indirizzo che ci servirà nell'aggiunta di una
Service Reference.
Il Client WCF
Ora per utilizzare il servizio dobbiamo costruire un client, quindi creiamo una
Console Application. Aggiungiamo una
Service Reference che costruisca la classe proxy per accedere al servizio, prima è necessario far partire il servizio (ctrl+f5) e digitare l'url del servizio.
Dopo aver selezionato il servizio, automaticamente nell'
App.config del client, Visual Studio ha creato tutti i parametri necessari al WCF, nei prossimi articoli ce ne occuperemo più approfonditamente.
Ora per eseguire Il nostro servizio nel
Main della applicazione creiamo una istanza della classe proxy ed eseguiamo il metodo del servizio stampando il messaggio che ci viene ritornato.
static void Main(string[] args)
{
ServiceReference.Service1Client service =
new ConsoleApplication1.ServiceReference.Service1Client();
Console.WriteLine(service.GetData(1));
}
Eseguendo l'applicazione (ctrl+f5) verrà visualizzato il messaggio del metodo
GetData().
Host personalizzato
Ora che abbiamo visto il progetto template di Visual Studio, proviamo a costruirci un nostro servizio personalizzato, in modo da conoscere meglio il
WCF.
Creiamo una nuova
Console Application e la chiamiamo myHost. Importiamo i namespaces e le References necessarie per il
WCF, che sono le seguenti:
- System.ServiceModel- System.Runtime.SerializationCominciamo col creare il nostro
Contract, e difiniamo un semplice metodo
HelloWorld.
[ServiceContract]
public interface myHostContract
{
[OperationContract]
string HelloWorld();
}
Definita l'interfaccia costruiamo una classe
myHostclass che implementa il contratto:
public class myHostclass : myHostContract
{
public string HelloWorld()
{
Console.WriteLine("New connection");
return "Hello World";
}
}
A questo punto dopo che abbiamo completato la definizione del
Contract, costruiamo il nostro
Host, indicando i due elementi mancanti:
Address e Binding.
ServiceHost myConsoleHost = new ServiceHost(typeof(myHostclass),new Uri "http://localhost:8080/myHost"));
Binding binding = new WSHttpBinding();
EndpointAddress address = new EndpointAddress("http://localhost:8080/myHost");
Per poter associare il
Binding e l'Address al nosto Host è necessario indicare un
ContractDescription:
ContractDescription description = ContractDescription.GetContract(typeof(myHostContract));
definiamo un
ServiceEndpoint e l'associamo all'host:
ServiceEndpoint endpoint = new ServiceEndpoint(description, binding, address);
myConsoleHost.Description.Endpoints.Add(endpoint);
l'Host è pronto, manca solo l'indicazione del
Behavior per l'interrogazione via HTTP:
ServiceMetadataBehavior metadata = new ServiceMetadataBehavior(); metadata.HttpGetEnabled = true;
myConsoleHost.Description.Behaviors.Add(metadata);
Apriamo l'Host in questo modo:
myConsoleHost.Open();
Console.WriteLine("In attesa...");
Console.ReadLine();
Per verificare il nostro servizio non dobbiamo far altro che eseguire la procedura di creazione del client vista precedentemente, indicando l'url del servizio ed eseguire il nostro
HelloWorld:
static void Main(string[] args)
{
ServiceReference.myHostContractClient myContract =
new myClient.ServiceReference.myHostContractClient();
Console.WriteLine(myContract.HelloWorld());
}
Host e App.config
Visto che Microsoft pensa sempre a come semplificare la vita a noi sviluppatori tutte le righe di codice che abbiamo scritto diventano inutili nel momento in cui definiamo i parametri direttamente nell'
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<!--- definizione del servizio -->
<service name="myHost.myHostclass" behaviorConfiguration="myHostBehavior">
<host>
<baseAddresses>
<!-- Base Address del servizio -->
<add baseAddress="http://localhost:8080/myHost"/>
</baseAddresses>
</host>
<!-- Endpoint con contratto, binding e address -->
<endpoint address="http://localhost:8080/myHost" binding="wsHttpBinding" contract="myHost.myHostContract"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="myHostBehavior">
<serviceMetadata httpGetEnabled="true"/> <!-- Behavior per la richeista http -->
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Con queste impostazioni creare il nostro Host è molto semplice, basta istanziare la classe
ServiceHost e aprire la connessione.
ServiceHost myConsoleHost = new ServiceHost(typeof(myHostclass));
myConsoleHost.Open();
Console.WriteLine("In attesa...");
Console.ReadLine();
Conclusioni e considerazioni
Dopo questa breve introduzione una domanda viene spontanea: cosa ne pensate ? Spero che anche voi come me siate rimasti affascinati da questo nuovo modo di concepire le applicazioni distribuite. Ora provate ad immaginare diverse applicazioni che interagiscono tutte con un protocollo diverso allo stesso servizio, e le novità non si fermano qui, con gli altri articoli che seguiranno a breve entreremo sempre più nel dettaglio di questo framework, che tra pochi mesi diventerà la soluzione primaria .NET per applicazioni distribuite.