Semplici operazioni di imaging con .Net 3.5 e WPF

18. luglio 2010 13.47

Lo scopo di questo breve tutorial è quello di mostrare come con poche righe di codice .Net 3.5 e Windows Presentation Foundation (WPF) ci permettono di aprire, modificare il colore di un’immagine e salvare il risultato finale. Per quanto riguarda la costruzione della GUI in XAML rimandiamo direttamente al progetto in allegato.

Come anticipato, il nostro scopo è quello di caricare un’immagine (per semplicità gestiremo immagini BMP, GIF e JPEG) in un oggetto del tipo System.Windows.Controls.Image, applicare un filtro all’immagine caricata (per semplicità convertiremo l’immagine in bianco e nero, ovvero in un’immagine con 1 bit di colore), visualizzeremo nel medesimo controllo il risultato e salveremo la stessa in un file (anch’esso del tipo BMP, GIF o JPEG).

Premettiamo che sfortunatamente WPF non ha ancora a disposizione dei controllo di apertura/salvataggio di un file, per cui saremo costretti ad includere nel nostro progetto anche la libreria System.Windows.Forms.

OpenFileDialog openFile = new OpenFileDialog();

openFile.Filter = "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif|JPEG files (*.jpg)|*.jpg";
openFile.ShowDialog();

fileToProcess = openFile.FileName;

if (fileToProcess != String.Empty || fileToProcess != "")
{
    Uri myUri = new Uri(fileToProcess, UriKind.RelativeOrAbsolute);

    switch (openFile.FilterIndex)
    {
        case 0:
            BmpBitmapDecoder decoder = new BmpBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource bitmapSource = decoder.Frames[0];
            mainImage.Source = bitmapSource;

            break;

         case 1:
             GifBitmapDecoder gifDecoder = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
             BitmapSource gifBitmapSource = gifDecoder.Frames[0];
                        mainImage.Source = gifBitmapSource;

             break;

          case 3:
              JpegBitmapDecoder jpgDecoder = new JpegBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
              BitmapSource jpgBitmapSource = jpgDecoder.Frames[0];
              mainImage.Source = jpgBitmapSource;

              break;

          default:
              break;
      }
 }

Passo 1: caricamento dell’immagine nel controllo Image (mainImage).

OpenFileDialog openFile = new OpenFileDialog();

openFile.Filter = "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif|JPEG files (*.jpg)|*.jpg";
openFile.ShowDialog();

fileToProcess = openFile.FileName;

if (fileToProcess != String.Empty || fileToProcess != "")
{
    Uri myUri = new Uri(fileToProcess, UriKind.RelativeOrAbsolute);

    switch (openFile.FilterIndex)
    {
        case 0:
            BmpBitmapDecoder decoder = new BmpBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource bitmapSource = decoder.Frames[0];
            mainImage.Source = bitmapSource;

            break;

         case 1:
             GifBitmapDecoder gifDecoder = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
             BitmapSource gifBitmapSource = gifDecoder.Frames[0];
                        mainImage.Source = gifBitmapSource;

             break;

          case 3:
              JpegBitmapDecoder jpgDecoder = new JpegBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
              BitmapSource jpgBitmapSource = jpgDecoder.Frames[0];
              mainImage.Source = jpgBitmapSource;

              break;

          default:
              break;
      }
 }

Il codice precedente non ha bisogno di molte spiegazioni: tramite l’usuale controllo OpenFileDialog otteniamo il nome del file da caricare che andremo a “decodificare” tramite un’istanza della classe BmpBitmapDecodre/GifBitmapDecoder/JpgBitmapDecoder. A sua volta quest’oggetto restituirà un frame che contiene il “sorgente”, ovvero un’istanza di ImageSource che è il formato di “input” del controllo System.Windows.Controls.Image, ovvero l’oggetto che mostra a video l’immagine caricata dal file.

 

Passo 2: conversione in bianco e nero dell’immagine caricata.

FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();

newFormatedBitmapSource.BeginInit();
newFormatedBitmapSource.Source = (BitmapSource)mainImage.Source;
newFormatedBitmapSource.DestinationFormat = PixelFormats.BlackWhite;
newFormatedBitmapSource.EndInit();

Image myImage = new Image();
myImage.Source = newFormatedBitmapSource;
mainImage.Source = myImage.Source;

Anche in questo caso il codice è molto semplice: un oggetto FormatConvertedBitmap prenderà come sorgente l’immagine caricata nel controllo Image e tramite la proprietà DestinationFormat applicherà il filtro che abbiamo scelto, in questo caso il formato di pixel con 1 bit di colore.

 

Successivamente provvederemo a creare un’oggetto Image a partire dalla conversione appena operata che sarà la nuova “sorgente” del controllo Image che di conseguenza mostrerà l’immagine modificata.

 

Passo 3: Salvataggio su disco dell’immagine modificata.

SaveFileDialog saveFile = new SaveFileDialog();

saveFile.Filter = "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif|JPEG files (*.jpg)|*.jpg";
saveFile.ShowDialog();

fileToSave = saveFile.FileName;

if (fileToSave != String.Empty || fileToSave != "")
{
    double actualHeight = mainImage.RenderSize.Height;
    double actualWidth = mainImage.RenderSize.Width;
    double renderHeight = actualHeight * 1;
    double renderWidth = actualWidth * 1;

    RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
    VisualBrush sourceBrush = new VisualBrush(mainImage);
    DrawingVisual drawingVisual = new DrawingVisual();
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    using (drawingContext)
    {
        drawingContext.PushTransform(new ScaleTransform(1, 1));
        drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
    }

    renderTarget.Render(drawingVisual);

    switch (saveFile.FilterIndex)
    {
        case 1:
            BmpBitmapEncoder bmpEncoder = new BmpBitmapEncoder();
            bmpEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

            using (FileStream fileStream = new FileStream(fileToSave, FileMode.Create))
            {
                bmpEncoder.Save(fileStream);
                fileStream.Flush();
                fileStream.Close();
            }

            break;

        case 2:
            GifBitmapEncoder gifEncoder = new GifBitmapEncoder();
            gifEncoder.Frames.Add(BitmapFrame.Create(renderTarget));                        

            using (FileStream fileStream = new FileStream(fileToSave, FileMode.Create))
            {
                gifEncoder.Save(fileStream);
                fileStream.Flush();
                fileStream.Close();
            }

            break;

        case 3:
            JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
            jpgEncoder.QualityLevel = 100;
            jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

            using (FileStream fileStream = new FileStream(fileToSave, FileMode.Create))
            {
                jpgEncoder.Save(fileStream);
                fileStream.Flush();
                fileStream.Close();
            } 

            break;

        default:
            break;
    }
}

Questo metodo è un po’ più lungo dei precedenti ma alla fine non è molto complicato. Tramite l’usuale oggetto SaveFileDialog otteniamo il nome del file su cui salvare l’immagine che abbiamo precedentemente modificato. Calcoliamo altezza e larghezza dell’immagine mostrata a video e le stesse informazioni per l’immagine che andremo a salvare. Notiamo che in questo caso avviene una moltiplicazione per 1: stiamo semplicemente usando la scala 1:1.

 

Gli oggetti del tipo VisualBrush, DrawingVisual e DrawingContext ci permettono di “selezionare” l’immagine contenuta nel controllo Image a partire dal punto inizale di coordinate (0,0) al punto finale (actualWidth, actualHeight). Il risultato della selezione verrà “registrato” in un oggetto RenderTargetBitmap che non fa altro che convertire un oggetto “visual” appunto in una bitmap.

 

Lo switch successivo è molto semplice: a seconda del tipo di output scelto (bmp, gif o jpg) creeremo un oggetto “encoder” cui verrà aggiunto un frame contenente la bitmap precedentemente creata. Questo encoder possiede un metodo “save” che permette di salvare il contenuto dell’encodere in uno stream creato ad hoc. In questo caso lo stream su cui andremo a salvare è uno stream su file.

Mappare campi e proprietà con la reflection di .Net 3.5

18. luglio 2010 13.43

Il tutorial che vi propongo quest’oggi nasce da un’esigenza ben precisa: mi sono trovato a dover mappare due classi “identiche” se non nel fatto che la prima esponeva i propri dati privati attraverso proprietà pubbliche, la seconda rendendo pubblici proprio i campi dei dati. Sostanzialmente in codice

class GTPersonaPrimoTipo
{
    public String name;
    public String surname;
}

e

class GTPersonaSecondoTipo
{
    public String name { get; set; }
    public String surname { get; set; }
}

Il framework .Net ci viene incontro con la reflection grazie alla quale ho potuto scrivere il seguente metodo:

void mapObject(object typeOne, object typeTwo)
{
    Type type1 = typeOne.GetType();
    Type type2 = typeTwo.GetType();

    PropertyInfo[] property2 = type2.GetProperties();
    FieldInfo[] field1 = type1.GetFields();

    for (int i = 0; i < property2.Length; i++)
    {
        if (property2[i].Name == field1[i].Name)
        {
            String sValue = field1[i].GetValue(typeOne).ToString();
            property2[i].SetValue(typeTwo, sValue, null);
        }
    }
}

Metodo molto semplice: passo due oggetti generici alla metodo, ricavo il loro tipo. Ottengo un array di oggetti ProperyInfo che conterrà le proprietà della classe GTPersonaSecondoTipo e un array di oggetti FieldInfo che conterrà i campi pubblici della classe GTPersonaPrimoTipo.
A questo punto non mi resta che da ciclare sulle proprietà della seconda classe, e quando il nome della proprietà della seconda classe è uguale al nome del campo della prima, "copiare" il valore del campo nella proprietà.

 

Ecco come poter testare il codice precedente in un progetto GTPersonaPrimoTipo:

static void Main(string[] args)
{
    GTPersonaPrimoTipo personaPrimoTipo = new GTPersonaPrimoTipo();
    GTPersonaSecondoTipo personaSecondoTipo = new GTPersonaSecondoTipo();

    personaPrimoTipo.name = "Gennaro Eduardo";
    personaPrimoTipo.surname = "Tangari";

    mapObject(personaPrimoTipo, personaSecondoTipo);

    System.Console.WriteLine("{0}, {1}", personaSecondoTipo.surname.ToUpper(), personaSecondoTipo.name);
    System.Console.ReadLine();
}

Comprimere e decomprimere MemoryStream con DeflateStream e .Net

18. luglio 2010 13.40

A volte capita di dover comprimere/decomprimere dei flussi di dati in memoria perché magari li si deve spedire sulla rete tramite socket tcp, web services ecc. ecc. Il compito non è particolarmente difficile e come al solito il framework .Net ci viene incontro fornendoci le “basi” del piatto: MemoryStream per la gestione degli stream in memoria e GZipStream/DeflateStream (per la cui differenza vi rimando all’ottima documentazione su MSDN) per la compressione degli stream.

L’esempio che propongo di seguito mostra appunto l’utilizzo delle classi MemoryStream per il “trasporto” delle informazioni verso la classe “comprimente” che in questo caso ho scelto essere la DeflateStream.

Vediamo per prima cosa la compressione:

public static byte[] Comprimi(byte[] data)
{
     MemoryStream ms = new MemoryStream();
     DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress);
     ds.Write(data, 0, data.Length);
     ds.Flush();
     ds.Close();
     return ms.ToArray();
}

Il contenuto di questo metodo è molto semplice: si passa in input un array di byte, si crea un MemoryStream che conterrà il contenuto dell’array di byte in formato compresso, si crea un DeflateStream che avrà come primo parametro lo stream in cui verrà scritto ciò che si andrà a comprimere, e come secondo parametro la modalità di compressione (compressione/decompressione).

 

A questo punto tramite il metodo Write possiamo effettivamente scrivere nello stream di memoria l’array di byte compresso.

 

Qualche riga in più, ma non troppo, per il metodo di decompressione:

public static byte[] Decomprimi(byte[] data)
{
     MemoryStream ms = new MemoryStream(data);
     DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);

     Listl = new List();
     int theByte = ds.ReadByte();

     while (theByte != -1)
     {
          l.Add((byte)theByte);
          theByte = ds.ReadByte();
     }

     byte[] retVal = l.ToArray();         

     return retVal;
}

Vediamolo in dettaglio: creeremo un MemoryStream in cui caricheremo dentro l’array di byte compresso. Creeremo un oggetto DeflateStream il cui primo parametro questa volta sarà il MemoryStream con i valory di input e specificheremo che vogliamo applicare a questi una decompressione.

 

A questo punto leggeremo byte per byte il contenuto del DeflateStream e aggiungeremo il byte letto ad una lista di byte che verray alla fine convertita in un array di byte che finalmente conterrà il contenuto “scompattato” dell’array di partenza.

 

Se supponiamo d’avere un comune file di testo nella radice del disco “C”, un possibile esempio di quanto visto sopra potrebbe essere:

static void Main(string[] args)
{
     byte[] myarray = File.ReadAllBytes(@"C:\TEST.TXT");
     byte[] myArrayCompresso = Comprimi(myarray);
     byte[] myArrayDecompresso = Decomprimi(myArrayCompresso);

     String letto = System.Text.ASCIIEncoding.ASCII.GetString(myArrayDecompresso);
     System.Console.WriteLine("Ho letto:\n" + letto + "\n");

     Console.WriteLine("Premi  per terminare");
     Console.ReadLine();
}

Drag and drop su Windows Form con .Net e C#

18. luglio 2010 13.36

Il breve tutorial di quest’oggi ci guiderà a realizzare una semplice applicazione Windows Form sulla cui form principale sono presenti due ListBox sulle quali vogliamo abilitare ed implementare il drag and drop (sarà quindi possibile “trascinare” un elemento da una form all’altra oltre che su se stessa cambiandone l’ordine).

Tutto quello che dobbiamo fare è a questo punto creare un nuovo progetto Windows Form con Visual Studio e trascinare due ListBox, chiamandole rispettivamente lst1 e lst2 sulla form appena creata.

Possiamo utilizzare l’evento Load della form principale per popolare la prima lista oltre che abilitare il drag and drop su ambedue con il seguente codice:

 

lst1.Items.Add("Primo");
lst1.Items.Add("Secondo");
lst1.Items.Add("Terzo");
lst1.Items.Add("Quarto");
lst1.Items.Add("Quinto");
lst1.Items.Add("Sesto");
lst1.Items.Add("Settimo");

lst1.AllowDrop = true;
lst2.AllowDrop = true;

A questo punto dobbiamo prendere in considerazione tre eventi: il primo MouseDown sulla prima ListBox e i secondi due, DragOver e DragDrop, sulla seconda ListBox. Vediamo questi passi più in dettaglio

 

private void lst1_MouseDown(object sender, MouseEventArgs e)
{
     if (lst1.Items.Count > 0)
     {
          int index = lst1.SelectedIndex;

          string s = lst1.Items[index].ToString();

          DragDropEffects dde = DoDragDrop(s, DragDropEffects.All);

          if (dde == DragDropEffects.All)
          {
               lst1.Items.RemoveAt(lst1.SelectedIndex);
          }
     }
}

Il significato delle operazioni da compiere allo scatenarsi di quest’evento sono molto semplici: se abbiamo almeno un elemento sulla ListBox “sorgente” (che in questo caso è la prima) prendiamo l’indice dell’elemento selezionato ed otteniamo il testo dell’elemento stesso conservandolo in una stringa. A questo punto, tramite il metodo DoDragDrop possiamo iniziare l’operazione di trascinamento. Se il metodo stesso restituirà uno dei valori appartenenti all’enumerazione DragDropEffects.All, vorrà dire che il drag and drop è avvenuto correttamente e quindi possiamo rimuovere dalla ListBox l’elemento precedentemente selezionato.

 

Ora passiamo all’evento DragOver, scatenato dopo il DragEnter, sulla seconda ListBox: qui ci limiteremo ad informare che abbiamo accettato l’evento di drag and drop stesso:

private void lst2_DragOver(object sender, DragEventArgs e)
{
     e.Effect = DragDropEffects.All;
}

Non ci resta a questo punto che passare all’implementazione dell’ultimo evento sulla seconda ListBox: DragDrop

private void lst2_DragDrop(object sender, DragEventArgs e)
{
     if (e.Data.GetDataPresent(DataFormats.StringFormat))
     {
          string str = (string)e.Data.GetData(DataFormats.StringFormat);
          lst2.Items.Add(str);
     }
}

Le operazioni che l’evento compierà sono le seguenti: se il formato dei dati “trascinati” è una stringa, leggo la stringa stessa e l’aggiungo alla seconda ListBox.

 

Da notare che al compimento di quest’evento, nel MouseDown della prima ListBox leggeremo il valore “all” per dde il che ci permetterà di cancellare l’elemento dalla lista stessa.

Creare, pubblicare e consumare un WCF con Visual Studio 2008, .Net 3.5 e C#

18. luglio 2010 13.03

Il tutorial che vi propongo oggi è ben esplicato dal suo titolo: alla fine di queste pagine sarete in grado di creare un WCF, pubblicare con un’applicazione ad hoc scritta da voi stessi e consumarla con una vostra applicazione client.

Nella vita reale probabilmente non scrivere mai una vostra applicazione per fare l’host di un WCF, probabilmente utilizzere IIS che fa egregiamente questo lavoro, ma in alcuni casi potrebbe essere necessario farlo e sicuramente sapere che esiste questa possibilità oltre che saperla implementare è cosa buona e giusta.

 

Introduzione

Windows Communication Foundation o più brevemente WCF è un framework in cui la Microsoft fa confluire in un modello di programmazione unico tutte le precedenti tecnologie di comunicazione tra processi: WebServices, MSMQ, .Net Remoting ecc. ecc.

Cambiare la tecnologia con cui comunicare non significherà più, con WCF, riscrivere l’applicazione o il servizio, ma “semplicemente” riconfigurare WCF (tramite il file di configurazione dell’applicazione: in breve l’App.Config o il Web.Config a seconda dei casi) in modo tale da cambiarne il comportamento.

I mattoncini che compongono un WCF sono i seguenti: ServiceContract con i suoi OperationContract ovvero un’interfaccia (il ServiceContract) che descriverà cosa il WCF dovrà fare tramite i metodi da implementare (gli OperationContract). Il DataContract ovvero i dati che il servizio WCF e l’applicazione chiamante potranno scambiare e il connesso MessageContract ovvero come la struttura dati rappresentata da un DataContract può essere serializzata in un messaggio SOAP.

Importantissimo è poi il concetto di EndPoint che a sua volta è formato da tra elementi: Address ovvero l’indirizzo cui le applicazioni che devono inoltrare chiamate al servizio devono puntare, il Binding ovvero la modalità in cui il servizio viene esposto (Soap tramite basicHttpBindig/wsHttpBindig, oppure NetTCP, NetNamedPipe, MSMQ ecc. ecc.) e il Contract l’interfaccia che il WCF deve implementare.

Il bello di WCF, come accennato, è che per cambiare il suo comportamento in senso più esteso, quindi l’indirizzo cui può essere raggiunto, la modalità in cui il servizio espone i suoi metodi ecc. ecc. può essere cambiato a runtime, senza intervento dello sviluppatore semplicemente variando il file di configurazione dell’applicazione, dove tra i tag <System.ServiceModel>…</System.ServiceModel> vengono configurati i vari binding (e non solo…)

 

Parte I: Creazione del WCF

Avviare Visual Studio 2008 e creare un nuovo progetto del tipo “Class Library”, ovvero una semplice libreria DLL. Aggiungiamo un riferimento al componente System.ServiceModel e creiamo un nuovo file C# in cui andremo a dichiarare la nostra interfaccia chiamata IGTService:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace GTService
{
     [ServiceContract]
     interface IGTService
     {
          [OperationContract]
          String getHello();
     }
}

La descrizione dell’interfaccia è ben poca cosa: si “decora” la sua dichiarazione con la parola chiave [ServiceContract], e questo permetterà a WCF di capire che quest’interfaccia è quella del “contratto”, ovvero conterrà la definizione dei metodi che il WCF esporrà. Ogni metodo che dovrà essere esposto dovrà essere segnato come [OperationContract].

A questo punto possiamo aggiungere al progetto un nuovo file C# che conterrà una classe che implementerà l’interfaccia appena creata:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GTService
{
public class GTService : IGTService
{
#region IGTService Members

public string getHello()
{
System.Console.WriteLine("Ho ricevuto una richiesta per \"getHello\"");
return "Hello World!";
}

#endregion
}
}

L’implementazione dell’interfaccia del WCF non ha bisogno di ulteriori commenti: il “cuore” del nostro WCF è così completato.

 

Parte II: applicazione host

Quello che faremo ora è creare un’applicazione che esponga il servizi precedentemente creato: ciò avverrà attraverso la creazione di un’applicazione console. Come anticipato, ben difficilmente nella vita reale andremo ad esporre un WCF attraverso un’applicazione console, probabilmente lo faremo attraverso IIS o in casi più particolari attraverso un servizio di Windows: tuttavia in questo contesto l’applicazione host fa perfettamente il suo dovere e non ci fa perdere tempo si aspetti che esulano dallo scopo di questo breve tutorial.

In Visual Studio 2008 aggiungiamo alla soluzione precedentemente creata un nuovo progetto di tipo “Console Application”: come fatto per la libreria aggiungiamo un riferimento al componente System.ServiceModel ed aggiungiamo al main il codice seguente:

 

using (ServiceHost service = new ServiceHost(typeof(GTService.GTService)))
{
service.Open();

System.Console.WriteLine("Premi  per terminare il servizio");
System.Console.ReadLine();

service.Close();
}

Le operazioni compiute da questo programma sono molto semplici: un’istanza della classe ServiceHost permette di “ospitare” il nostro servizio. La comunicazione verrà aperta invocando il metodo Open. Com’è facilmente intuibile il servizio rimarrà in ascolto fin quando non verrà premuto un tasto ovvero fin quando non verrà invocato il metodo Close.

 

Parte III: Configurazione del servizio

Aggiungiamo alla nostra applicazione host il suo file di configurazione ed editiamolo, aggiungendovi la sezione System.ServiceModel come segue:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="GTService.GTService" behaviorConfiguration="GTServiceBehaviorConfiguration">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/GTService.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="GTService.IGTService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="GTServiceBehaviorConfiguration">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</system.serviceModel>
</configuration>

 

Vediamone velocemente il significato: nella sezione Services vengono aggiunti tutti i servizi esposti dal WCF, nel nostro caso è uno. Ogni tag Service descrive il servizi: gli viene dato un nome (che poi è quello che viene chiamato dal costruttore di ServiceHost) e viene specificato il behaviorConfiguration, ovvero la sezione di App.Config in cui verrà configurato il comportamento del servizio stesso.

Si aggiungono i baseAddress ovvero la base comune a tutti gl’indirizzi dei vari endpoint (per indirizzi s’intende proprio l’indirizzo del servizio).

Si aggiunge un entpoint il cui address è vuoto proprio perché non si vuole aggiungere null’altro al baseAddress, si specifica un binding, in questo caso il basicHttpBindig (assimilabile al vecchio web service .asmx di .Net 2.x e precedenti) e l’interfaccia che definisce il contratto.

Aggiungiamo poi un serviceBehaviors, ovvero un comportamento in cui semplicemente si dice al WCF di pubblicare il WSDL.

A questo punto avviando il servizio ed aprendo con un browser l’indirizzo dell’endpoint possiamo verificare che il tutto venga effettivamente esposto se otterremo qualcosa di simile a quanto visibile a seguito:

 

 

Guardando bene la risposta del browser abbiamo già le istruzioni per creare un semplice client per il nostro servizio, cosa che andremo a fare nella sezione seguente. 

 

Parte IV: creazione dell’applicazione client

Per prima cosa, così come specificato dalla risposta del browser precedentemente ottenuta, dobbiamo generare le classi e il file di configurazione che permetteranno alla nostra applicazione client d’invocare il servizio: apriamo un prompt dei comandi di Visual Studio e digitiamo il comando:

 

svcutil.exe http://localhost:8888/GTService.svc?wsdl

 

al seguito dell’esecuzione di questo comando verranno generati due file: GTService.cs e App.Config. Creiamo una nuova Console Application ed aggiungiamola alla nostra soluzione in Visual Studio ed aggiungiamo questi due file al progetto appena creato.

Editiamo come segue il main della nuova Console Application:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestClient;

namespace TestClient
{
class Program
{
static void Main(string[] args)
{
using (GTServiceClient client = new GTServiceClient())
{
client.Open();
String str = client.getHello();
client.Close();

System.Console.WriteLine("Messaggio : " + str);
System.Console.ReadKey(true);
}
}
}
}

La descrizione di quanto fatto è molto semplice: nel file GTService.cs è dichiarata una classe GTServiceClient che permette d’iniziare la comunicazione con il servizio e fra le tante altro cose, c’è la dichiarazione al metodo del servizio getHello. Mandando in esecuzione quest’applicazione otterremo l’output su console del messaggio ritornato dal metodo getHello.

Ci sarebbero tantissime altre cose da dire sull’argomento, ma andrebbero fatte in una sede diversa da quella di un tutorial introduttivo come questo.

Pillole di .Net 4.0: JumpiList

18. luglio 2010 12.57

Windows Vista prima e Windows 7 successivamente hanno (finalmente) portato un po’ di rinnovamento alla GUI di Windows che tema dei colori a parte, era rimasta sostanzialmente immutata dai tempi di Windows 95. Lo stesso framework .Net, con l’introduzione di WPF, con la sua versione 3.x, ha portato nuovi strumenti che permettono agli sviluppatori di realizzare applicazioni con interfacce grafiche più accattivanti.

In questo breve tutorial vedremo come, su Windows 7, sfruttare le nuove jumplist della taskbar: le jumplist non sono altro che quelle finestre “baloon” che si aprono al click del tasto destro del mouse cliccando su un’icona della taskbar come mostrato di seguito.

 

 

Gli strumenti utilizzati sono: .Net Framework 4.0 e Visual Studio 2010.

Per prima cosa apriamo Visual Studio 2010 e creiamo un nuovo progetto del tipo “WPF Application” e modifichiamo il target al framework 4.0.

 

A questo punto importiamo il namespace System.Windows.Shell 

using System.Windows.Shell;

 

Siamo ora pronti a creare la nostra JumpList aggiungendo il nostro codice al metodo

 

private void Window_Loaded(object sender, RoutedEventArgs e);

Premessa: quello che andremo a fare è creare un nuovo “gruppo” denominato “Link utili” a cui aggiungeremo un link ad Internet Explorer (che nel mio caso, avendo Windows 7 a 64 bit si troverà al path: “C:\Program Files (x86)\Internet Explorer\iexplore.exe”).

Il come farlo è mostrato di seguito con i commenti che sono più che sufficienti a descrivere le azioni compiute:

 

// Dichiaro l'oggetto JumpTask da aggiungere alla JumpList
JumpTask jumpTask1 = new JumpTask();

// Modifico il comportamento del JumpTask
jumpTask1.ApplicationPath = @"C:\Program Files (x86)\Internet Explorer\iexplore.exe";
jumpTask1.IconResourcePath = @"C:\Program Files (x86)\Internet Explorer\iexplore.exe";
jumpTask1.Title = "Internet Explorer";
jumpTask1.Description = "Apri Internet Explorer.";
jumpTask1.CustomCategory = "Link utili";

// Aggiungo il JumpTask alla JumpList
JumpList jumpList2 = new JumpList();
jumpList2.JumpItems.Add(jumpTask1);

// Aggiungo la JumpList alla nostra applicazione
JumpList.SetJumpList(App.Current, jumpList2);

Info su di me

Il mio nome è Gennaro Eduardo Tangari e sono uno sviluppatore certificato su tecnologie Microsoft .NET che lavora prevalentemente su applicazioni web enterprise e mobile.

Attualmente lavoro presso Value Team S.p.A. con la qualifica di Senior Consultant su progetti internazionali e nazionali basati su tecnologie Microsoft, con particolare cura verso Microsoft Dynamics CRM.

Questo blog nasce dall'esigenza di condividere esperienze e metodologie acquisite durante gli anni di lavoro cercando di restituire alla rete quello che la rete stessa mi ha dato: informazioni utili.

 

Certificazione

 

 

QRCode