CSharp:WCF
From Aino Wiki
Contents
Definizione
Windows Communication Foundation (WCF) presente dalla versione 3.0 del .NET Framework, ha il principale scopo di rappresentare i modelli di comunicazione tra sistemi distribuiti. Per informazioni vedere: HTML.it
Era necessario unificare in un unico componente i metodi supportati da Microsoft per il trasporto di informazioni in ambienti distribuiti. WCF fornisce un meccanismo unitario per implementare: Web Services, Web Services Enhancementa (WSE), Remoting, Enterprise Services, MSMQ (Message Quequing).
Questo modello unificato di programmazione è basato sulle linee guida dell'architettura SOA.
Con WCF possiamo creare un semplice servizio ed esportarlo tramite IIS come un Web Service (basato sul protocollo HTTP) oppure utilizzabile col protocollo TCP/IP.
In Dettaglio
(da HTML.it) Un servizio è rappresentato da una classe detta appunto classe di servizio, compilata in un’assembly .NET, che per essere eseguita va “ospitata” in applicazioni che fungono da “host” per il servizio stesso.
Tali applicazioni possono essere IIS, WAS, servizi Windows o semplici eseguibili (quindi Windows Form, applicazioni WPF o console application).
L’applicazione host e i vari client (rispettivamente chi offre e chi consuma il servizio) parlano tra loro attraverso delle “terminazioni” dette Endpoint.
Struttura
Ogni servizio WCF è basato sul concetto di "service class" e "host application".
L’applicazione host e i vari client parlano tra loro con delle “terminazioni” dette Endpoint, un WCF è una collezione di EndPoint.
Ogni Endpoint è formato da tre componenti logiche, che rispondono ad altrettante domande (dove? come? cosa?):
- Address (dove), è l'indirizzo al quale il servizio risponde. L'indirizzo è composto da un URI (indirizzo fisico del servizio), una "Identity" ed una lista di "Header".
- Binding (come), sono le azioni intraprese per occuparsi del trasporto dell'informazione.
- Contract (cosa), specifica l’elenco delle operazioni fornite dal servizio stesso (le API).
<system.serviceModel>
.
Per realizzare un client, dobbiamo creare una classe proxy che rappresenti la “service class” (lato client) esposta dal servizio WCF (lato server), per poi definire il suo Endpoint all’interno del file di configurazione (nel caso di un’applicazione ASP.NET quindi, all’interno del file web.config
).
Hosting
Come intuito ci sono 2 tipologie di servizio:
- WCF Service Application, per creare un servizio che DOVRA' essere hosted in IIS/WAS; questa tipologia implica l'uso del file *.svc.
- WCF Service Library, per creare un servizio host-indipendent che è in ascolto su una determinata porta me che non necessita di IIS o altro host. Può esser tenuto in esecuzione dal tool
WCF Service Host
(wcfSrvHost.exe
).
Hosting and consuming WCF
Fuori da Visual Studio:
WcfSvcHost.exe /service:WcfServiceLibrary1.dll /config:WcfServiceLibrary1.dll.config /client:"path/CustomClient.exe" /clientArg:"arguments that are passed to Client"
Windows Service
- Hosting come Windows Service, esempio step by step c-sharpcorner.com.
- Link interno Come creare un servizio
Esempio di VS Solution con WCF e Servizio Windows:
...Aggiungere una semplice reference al progetto WCF, non una Service Reference...
Codice del servizio creato:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceModel; using System.ServiceProcess; using System.Text; using System.Threading.Tasks; namespace WinService_PMSME { public partial class Service1 : ServiceBase { ServiceHost m_objHosting; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { m_objHosting = new ServiceHost(typeof(Wcf_App_PMSME.PMSME_AService)); m_objHosting.Open(); } protected override void OnStop() { if (m_objHosting != null) m_objHosting.Close(); } } }
Installazione
Seguire la procedura per aggiungere l'installatore al servizio, dettagli qui. Il tutorial di Microsoft suggerisce che dopo aver selezionato 'serviceProcessInstaller1', nelle proprietà si imposti l'attributo "Account" a NetworkService ma non è detto.
Se si dovesse ricevere un errore "Access Denied" provare, dalle proprietà del servizio, a cambiare selezionando Local System account.
Installazione del Servizio (da VisualStudio: Tools\Command Line\Developer Command\Prompt):
C:\..\>installutil WinService_PMSME.exe
Disinstallazione:
C:\..\>installutil /u WinService_PMSME.exe
Progetto in VS
Configurazione
Service References
Configurazioni particolari, tipo indicare la porta del servizio etc, van fatti esplicitamente col tasto Dx del Mouse sulla specifica reference.
Infine configurare i parametri interessati
Test
WCF Test Client
Tool incluso in visual studio che dal file svc di un WCF consente di creare i DTO della Request e visualizzare la Response:
Esempi
Esempio 1 (Server Integrato VS)
Per esempio possiamo scegliere di creare una applicazione WCF Service Library, host-indipendent che non necessiti di IIS.
In questo esempio creeremo una solution (chiamata "Test_WCF_ClientServer") con:
- un Progetto (Client) costituito da una Windows Application;
- un Progetto (Server WCF) contenente gli EndPoint di servizio consumati nel progetto Client.
Progetto WCF
Creiamo prima il progetto con la Windows Application che fungerà da Client, la chiamerò "WcfServiceLibrary_Test".
Vengono creati automaticamente 2 files IService1.cs e Service1.cs
In dettaglio segue il codice generato automaticamente. Notare gli attributi [ServiceContract] della classe interfaccia (IService1) e [OperationContract] associata ai metodi previsti nell'interfaccia.
namespace WcfServiceLibrary_Test { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together. [ServiceContract] public interface IService1 { [OperationContract] string GetData(int value); [OperationContract] CompositeType GetDataUsingDataContract(CompositeType composite); // TODO: Add your service operations here } // Use a data contract as illustrated in the sample below to add composite types to service operations. [DataContract] public class CompositeType { bool boolValue = true; string stringValue = "Hello "; [DataMember] public bool BoolValue { get { return boolValue; } set { boolValue = value; } } [DataMember] public string StringValue { get { return stringValue; } set { stringValue = value; } } } }
Service1.cs
namespace WcfServiceLibrary_Test { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together. public class Service1 : IService1 { /// <summary> /// Esempio di implementazione di una chiamata a metodo con dato semplice /// in input ed in output /// </summary> /// <param name="value"></param> /// <returns></returns> public string GetData(int value) { return string.Format("Hai digitato: {0}", value); } /// <summary> /// Esempio di implementazione di una chiamata a metodo con dato complesso /// in input ed in output /// </summary> /// <param name="composite"></param> /// <returns></returns> public CompositeType GetDataUsingDataContract(CompositeType composite) { if (composite == null) { throw new ArgumentNullException("composite"); } if (composite.BoolValue) { composite.StringValue += "Suffisso"; } return composite; } } }
Ed il file di configurazione App.config come segue
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation debug="true" /> </system.web> <!-- When deploying the service library project, the content of the config file must be added to the host's app.config file. System.Configuration does not support config files for libraries. --> <system.serviceModel> <services> <service name="WcfServiceLibrary_Test.Service1"> <host> <baseAddresses> <add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary_Test/Service1/" /> </baseAddresses> </host> <!-- Service Endpoints --> <!-- Unless fully qualified, address is relative to base address supplied above --> <endpoint address="" binding="basicHttpBinding" contract="WcfServiceLibrary_Test.IService1"> <!-- Upon deployment, the following identity element should be removed or replaced to reflect the identity under which the deployed service runs. If removed, WCF will infer an appropriate identity automatically. --> <identity> <dns value="localhost"/> </identity> </endpoint> <!-- Metadata Endpoints --> <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> <!-- This endpoint does not use a secure binding and should be secured or removed before deployment --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the value below to false before deployment --> <serviceMetadata httpGetEnabled="True"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="True" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Progetto Client
Si aggiunge la "Service Reference..." nel progetto appena completato prima.
Per avere la seguente nuova Reference:
Contenuto del Form1.cs
using System; using System.Windows.Forms; using Test_WCF_ClientServer.ServiceReference1; // WCF namespace Test_WCF_ClientServer { public partial class Form1 : Form { private CompositeType m_ct = new CompositeType(); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; try { Service1Client srv = new Service1Client(); CompositeType ct_Out = new CompositeType(); m_ct = new CompositeType() { BoolValue = ChkStringValue.Checked, StringValue = " cicatost " }; string outUno = srv.GetData(11); ct_Out = srv.GetDataUsingDataContract(m_ct); LblOutput_GetData.Text = outUno; LblOutput_GetDataUsingDataContract.Text = ct_Out.StringValue; MessageBox.Show("ok"); } catch (Exception) { throw; } finally { // Impostazione del puntatore con la freccia di default Cursor.Current = Cursors.Default; } } } }
app.config con l'aggiuta dei riferimenti al WCF "ServiceReferences"
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IService1" /> </basicHttpBinding> </bindings> <client> <endpoint address="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary_Test/Service1/" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" /> </client> </system.serviceModel> </configuration>
Esecuzione
Chiamando dal browser l'URI dell'endPoint
Particolare del Servizio del WCF esposto in automatico da VisualStudio
Esecuzione della applicazione Windows Form Client di test
Esempio 2 (Uso IIS)
Caso in cui il WCF è hostato su IIS
- Progetto completo usando IIS per l'hosting nikpatel
- Configurare WCF (VS 2012) hosting su IIS debugmode
- Tutorial (VS 2008 fwk 3.5): wcftutorial (afferma però che IIS supporta solo protocollo HTTP ...)
- Tutorial: c-sharpcorner
Problemi e soluzioni
Strumenti di trace
Tra i tools utili ad indagare sul contenuto dei messaggi inviati agli endpoint WCF c'è "service trace viewer" di Miscosoft, scaricabile da qui. I files avranno estensione *.svclog
Service References
References.CS vuoto
Nella configurazione va cambiato "REuse type in specific referenced assembly"
Mappa e Link
Parole chiave: