In questo articolo viene descritto come creare un servizio WCF che accetta comandi http come GET e POST, ed un client per invocare i comandi da remoto.

Per iniziare dobbiamo creare una nuova soluzione in Visual Studio (il presente esempio è stato creato con Visual Studio 2010), con nome ServiceApp e ti tipo Windows Forms Application.
Quindi aggiungiamo un nuovo progetto sempre di tipo Windows Forms Application ma con nome ClientApp.

Nel progetto ServiceApp aggiungiamo un nuovo file di tipo “Application Configuration File” e con nome App.config, una classe con nome Service1 e un’interfaccia IService1.

Il file App.config viene utilizzato per configurare il servizio WCF, è possibile configurare i servizi WCF anche mediante programmazione ma la configurazione attraverso file presenta vantaggi in termini di flessibilità, manutenzione e configurazione ad applicazione ultimata.

Al progetto ServiceApp deveno essere aggiunti i riferimenti agli assembly:

·         System.ServiceModel.dll;

·         System.ServiceModel.Web.dll;

·         System.Runtime.Serialization.dll;

Al progetto ClientApp devono essere aggiunti i riferimenti agli assembly:

·         System.ServiceModel.dll;

·         System.Runtime.Serialization.dll;

Nel progetto ClientApp deve anche essere aggiunto un riferimento al progetto ServiceApp

Il risultato finale è qualcosa del tipo:

 

All’interno del file IService1.cs è presente il contratto entro cui chi vuole comunicare con il servizio si deve attenere:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.Text;

using System.ServiceModel.Web;

namespace WcfRestJsonExample

{

   [ServiceContract]

   public interface IService1

   {

      [OperationContract]

      [WebInvoke(Method = "GET", UriTemplate = "/GetData", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

      string GetData();

      [OperationContract]

      [WebInvoke(Method = "GET", UriTemplate = "/CompositeType?boolValue={boolValue}&stringValue={stringValue}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

      CompositeType GetCompositeType(Boolean boolValue, String stringValue);

      [OperationContract]

      [WebInvoke(Method = "POST", UriTemplate = "/CompositeType", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

      bool SaveCompositeType(CompositeType compositeType);

      [OperationContract]

      [WebInvoke(Method = "POST", UriTemplate = "/UploadFile", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

      int UploadData(FileData fileInfo);

   }

   [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; }

      }

      public override string ToString()

      {

         return String.Format("CompositeType: BoolValue={0}; StringValue={1}", BoolValue, StringValue);

      }

   }

   [DataContract]

   public class FileData

   {

      [DataMember]

      public string Name

      {

         get;

         set;

      }

      [DataMember]

      public byte[] Content

      {

         get;

         set;

      }

   }

}

Il file Service1.cs contiene l’implementazione dell’interfaccia IService1.cs che definisce il contratto del servizio WCF:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.Text;

namespace WcfRestJsonExample

{

   [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]

   public class Service1 : IService1

   {

      public string GetData()

      {

         return DateTime.Now.ToString();  

      }

      public CompositeType GetCompositeType(Boolean boolValue, String stringValue)

      {

         return new CompositeType() { BoolValue = boolValue, StringValue = stringValue };

      }

      public bool SaveCompositeType(CompositeType compositeType)

      {

         System.Diagnostics.Trace.WriteLine(compositeType);

         return true;

      }

      public int UploadData(FileData fileInfo)

      {

         return fileInfo.Content.Length;

      }

   }

}

Nel file App.config dobbiamo inserire i parametri di configurazione del servizio:

<?xml version="1.0"?>

<configuration>

   <system.web>

      <compilation debug="true"/>

      <httpRuntime maxRequestLength="524288" />

   </system.web>

   <system.serviceModel>

      <bindings>

         <webHttpBinding>

            <binding name="StreamedRequestWebBinding"

                     bypassProxyOnLocal="true"

                     useDefaultWebProxy="false"

                     hostNameComparisonMode="WeakWildcard"

                     sendTimeout="10:15:00"

                     openTimeout="10:15:00"

                     receiveTimeout="10:15:00"

                     maxReceivedMessageSize="2147483647"

                     maxBufferSize="2147483647"

                     maxBufferPoolSize="2147483647"

                     transferMode="StreamedRequest">

               <readerQuotas maxArrayLength="2147483647"

                             maxStringContentLength="2147483647" />

            </binding>

         </webHttpBinding>

      </bindings>

      <services>

         <service name="WcfRestJsonExample.Service1" behaviorConfiguration="ServiceBehaviour">

            <host>

               <baseAddresses>

                  <add baseAddress="http://localhost:50000/WcfRestJsonExample/"/>

               </baseAddresses>

            </host>

            <endpoint address ="" binding="webHttpBinding" bindingConfiguration="StreamedRequestWebBinding" contract="WcfRestJsonExample.IService1" behaviorConfiguration="web">

            </endpoint>

         </service>

      </services>

      <behaviors>

         <serviceBehaviors>

            <behavior name="ServiceBehaviour">

               <serviceMetadata httpGetEnabled="true"/>

               <serviceDebug includeExceptionDetailInFaults="false"/>

            </behavior>

         </serviceBehaviors>

         <endpointBehaviors>

            <behavior name="web">

               <webHttp/>

            </behavior>

         </endpointBehaviors>

      </behaviors>

   </system.serviceModel>

</configuration>

Infine dobbiamo ospitare il servizio, visto che abbiamo scelto un progetto di tipo Windows Forms Application per il progetto ServiceApp, possiamo inserire creare l’istanza e l’apertura del servizio sull‘evento di OnLoad della finestra principale dell’applicazione ServiceApp:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.ServiceModel;

namespace ServiceApp

{

   public class Form1 : Form

   {

      private ServiceHost m_serviceHost;

      private WcfRestJsonExample.IService1 m_service1;

      /// <summary>

      /// Required designer variable.

      /// </summary>

      private System.ComponentModel.IContainer components = null;

      public Form1()

      {

         InitializeComponent();

      }

      protected override void OnLoad(EventArgs e)

      {

         m_service1 = new WcfRestJsonExample.Service1();

         m_serviceHost = new ServiceHost(m_service1);

         m_serviceHost.Open();

      }

      /// <summary>

      /// Clean up any resources being used.

      /// </summary>

      /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>

      protected override void Dispose(bool disposing)

      {

         if (disposing && (components != null))

         {

            m_serviceHost.Close();

            m_service1 = null;

            components.Dispose();

         }

         base.Dispose(disposing);

      }

      #region Windows Form Designer generated code

      /// <summary>

      /// Required method for Designer support - do not modify

      /// the contents of this method with the code editor.

      /// </summary>

      private void InitializeComponent()

      {

         this.SuspendLayout();

         //

         // Form1

         //

         this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

         this.ClientSize = new System.Drawing.Size(284, 262);

         this.Name = "Form1";

         this.Text = "Form1";

         this.ResumeLayout(false);

      }

      #endregion

   }

}

A questo punto possiamo passare al progetto ClientApp che ha il compito di invocare il metodi del servizio pubblicati attraverso il contratto WCF.

Il servizio presenta un metodo invocabile attraverso un comando HTTP di tipo GET con la seguente firma:

[OperationContract]

[WebInvoke(Method = "GET", UriTemplate = "/CompositeType?boolValue={boolValue}&stringValue={stringValue}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

CompositeType GetCompositeType(Boolean boolValue, String stringValue);

 

Se vogliamo richiamare il metodo sopraindicato con un commando HTTP di tipo GET dobbiamo utilizzare un oggetto WebClient:

WebClient client = new WebClient();

byte[] data = client.DownloadData(URL_ROOT + "CompositeType?boolValue=true&stringValue=get_object_to_test");

Stream stream = new MemoryStream(data);

DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(CompositeType));

CompositeType result = obj.ReadObject(stream) as CompositeType;

 

Se vogliamo invece invocare un comando HTTP di tipo POST, dobbiamo possiamo utilizzare il metodo del servizio che presenta la seguente firma:

[OperationContract]

[WebInvoke(Method = "POST", UriTemplate = "/CompositeType", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

bool SaveCompositeType(CompositeType compositeType);

Invocabile attraverso l’oggetto WebClient nel seguente modo:

WebClient client = new WebClient();

client.Headers["Content-type"] = "application/json";

FileData fileInfo = new FileData();

fileInfo.Name = "Test.txt";

fileInfo.Content = Get1MBFile();

MemoryStream stream = new MemoryStream();

DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(FileData));

serializer.WriteObject(stream, fileInfo);

byte[] data = client.UploadData(URL_ROOT + "UploadFile", "POST", stream.ToArray());

stream = new MemoryStream(data);

serializer = new DataContractJsonSerializer(typeof(int));

int result = (int)serializer.ReadObject(stream);