Archivi tag: Visual Studio

Estendere il WebClient per gestire un CookieStore

In C# , le system.net mettono a disposizione un oggetto chiamato WebClient per fare delle chiamate http in post a risorse identificate da un URI.

Nel mio caso l’ho utilizzato per fare delle chiamate dal CodeBehind di un applicazione web, per interrogare dei servizi web esposti in maniera restfull che accettavano dati in POST.

Dovendo gestire la sessione con questi servizi di backend e a volte avendo la necessità di dovergli pasare dei Cookie di autenticazione o altri cookie , mi sono trovato a doverlo estendere (per non lavorare direttamente con il WebRequest, oggetto su cui poggia il WebClient).

Il webclient offre pochissime funzionalità, ma estenderlo è molto facile.

In questo esempio aggiungiamo la possibilità di creare un proprio CookieStore, prima di una chiamata, in modo da potergli passare tutti i cookie (presi ad esempio dalla Request arrivata alla nostra pagina aspx) necessari al servizio che risponde all’URI interrogata.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;

using System.Net;

using System.Web;

public class ExtendedWebClient : WebClient

{

    private CookieContainer m_container = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)

    {

        WebRequest request = base.GetWebRequest(address);
        HttpWebRequest webRequest = request as HttpWebRequest;
        if (webRequest!=null){
            webRequest.CookieContainer = m_container;
        }
        return request;
    }

    public void SetCookies(HttpCookieCollection collection,string domain){
        m_container = new CookieStore();
        for (int j=0;j<collection.Count;j++){
            HttpCookie httpCookie = collection.Get(j);
            Cookie cookie = new Cookie();
            cookie.Domain = domain;
            cookie.Expires = httpCookie.Expires;  
            cookie.Name = httpCookie.Name;
            cookie.Path = httpCookie.Path;
            cookie.Secure = httpCookie.Secure;
            cookie.Value = httpCookie.Value;
            m_container.Add(cookie);
        }
    }
}

Oltre a gestire il cookieStore, dobbiamo preoccuparci della conversione dei cookies da HttpCookie (arrivati dalla Request) a quelli più dettagliati della System.Net.

Per utilizzare il nostro nuovo webclient e passargli i cookie possiamo fare in questo modo:

1
2
3
4
5
    ExtendendWebClient client = new ExtendedWebClient();
    client.SetCookies(request.Cookies,request.Url.Host);
    byte[] data = client.DownloadData("http://www.google.it");
    System.Text.Encoding enc = System.Text.Encoding.UTF8;
    string output = enc.GetString(data);

In questo modo tutti i cookie vengono impostati nel webclient prima di eseguire la webRequest.

Giocando con il parametro Domain, possiamo andare a filtrare i cookie che ci interessano per la chiamata in questione.

QuadTree in c# per spatial query

Sicuramente con le estensioni spatial della quasi totalità degli rdbms in circolazione, l’utilizzo dei QuadTree e di sistemi proprietari per il posizionamento  e l’interrogazione spaziale di insiemi di coordinate e oggetti, potrebbe risultare obsoleto. In realtà ci sono ancora tantissimi casi e campi di applicazione in cui risultano fondamentali, come lo sviluppo di applicazioni pda, giochi, e tutti quei casi in cui non sia possibile utilizzare un database sql.

Essendomi trovato nell’ultimo caso descritto per motivi di lavoro e forte dell’esperienza nello sviluppo di prototipi di videogames acquisita per hobby negli anni passati, ho adottato questa soluzione per un applicazione web in cui era fondamentale fare delle query spaziali su un insieme di punti (descritti da longitudine e latitudine), per geolocalizzare dei punti di interesse intorno alla mia posizione entro un certo raggio, presi da dei file xml.

Per facilità e velocità mi sono basato sull’articolo scritto da Michael Coyle su CodeProject.com:

http://www.codeproject.com/KB/recipes/QuadTree.aspx

Un QuadTree è un modo di ripartire lo spazio e facilitare le query su sistemi 2D, molto utilizzato nei GIS in generale, o nella gestione della posizione degli oggetti nei videogames.

Il QuadTree è apppunto un albero formato da quadrati. Lo spazio viene ripartito in regioni quadrate suddivise in 4 quadranti ,partendo dalla regione che contiene tutto fino al livello minimo da noi definito, in maniera ricorsiva. Quindi ogni quadrante viene poi ulteriormente suddiviso.

Per eseguire delle query su un quadtree basta poi effettuare il traversing dell’albero ed eseguire delle semplici intersezioni per capire quali oggetti sono posizionati all’interno di una determinata regione (che è l’input della ricerca).

Questo permette di eseguire ricerche molto veloci su insiemi statici di coordinate. Ovviamente è un albero statico, che nell’algoritmo cosi come proposto non permette un dinamismo nella gestione delle regioni I(in quanto andrebbe ricalcolata la struttura ad ogni modifica), ma è molto semplice da realizzare, ed il punto di partenza fondamentale è conoscere i confini dell’area che andremo a gestire..

Nel mio caso dovendo rappresentare dei punti di interesse sparsi sul suolo italiano, ho acquisito il punto centrale dell’italia e calcolato un quadrato che la contenesse tutta, e poi ho trasformato le coordinate geografiche in coordinate 2d, utilizzando gli stessi algoritmi di google maps, quindi con il fattore di zoom e tutto il resto.

Questa è la funzione che ho usato per la conversione di coordinate geografiche in coordinate schermo (x,y):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static PointF Geographical2Screen(Position position)
{
//converte le coordinate in pixel

float x;
float y;

double xD = (position.Longitude - mapLongitude) / resolution;
double yD = Math.Log(Math.Tan(Math.PI * (0.25 + position.Latitude / 360))) * u180dPiResolution;

x = Convert.ToSingle(xD + viewWidthHalf);
y = Convert.ToSingle((y0 - yD) + viewHeightHalf);

return new PointF(x, y);
}

dove per costanti ho usato, ipotizzando di inscrivere tutta l’area in un quadrato di 1024 pixel per 1024 pixel e usato un fattore di zoom che mi permettesse di mantenere tutta la mappa d’italia in questo quadrato .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static float WIDTH = 1024F;
public static float HEIGHT = WIDTH;
public static float CENTERMAP = WIDTH /2;
public static float TOTALPIXEL = WIDTH;

public static int zoom = 6;
public static double resolution = 360.0 / (Math.Pow(2,zoom) * 256);
public static double u180dPiResolution = 40.7436654315252 * Math.Pow(2, zoom);

public static double mapLatitude = 41.8719400F;
public static double mapLongitude = 12.5673800F;

public static double y0 = Math.Log(Math.Tan(Math.PI * (0.25 + mapLatitude / 360))) * u180dPiResolution;
public static float viewWidthHalf = WIDTH / 2.0f;
public static float viewHeightHalf = HEIGHT / 2.0f;

Fatto questo, ho costruito il mio quadtree a partire dal nodo principale:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class QuadTree
{

QuadTreeNode m_root;
RectangleF m_rectangle;

//solo per funzionalita di paint
public delegate void QTAction(QuadTreeNode obj);

public QuadTree(RectangleF rectangle)
{
m_rectangle = rectangle;
m_root = new QuadTreeNode(m_rectangle);
}

public int Count { get { return m_root.Count; } }

public void Insert(IQuadPoint item)
{
m_root.Insert(item);
}

public ListQuery(RectangleF area)
{
return m_root.Query(area);
}

public void ForEach(QTAction action)
{
m_root.ForEach(action);
}
}

Il delegato QTAction viene usato per poter rappresentare ad esempio tramite delle paint i nodi e i quad nel viewer.(un callback per il traversing, e per ogni elemento, disegno..)

il punto definito come risultato e’ un interfaccia da me cosi definita e che serve a markare gli oggetti che avranno la possibilità di essere inseriti nella struttura (per i fini della ricerca l’importante che l’oggetto da trovare abbia una posizione X,Y)

1
2
3
4
public interface IQuadPoint
{
PointF Point { get; }
}

Fatto questo passo alla definizione del nodo del quad, dove risiede l’implementazione ricorsiva della ricerca:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
public class QuadTreeNode
{
//area occupata da questo nodo
RectangleF m_bounds;

//contenuto del nodo
List m_contents = new List();

//figli di questo nodo
List m_nodes = new List(4);

static int maxElements = 50;
static int minSize = 10;
public QuadTreeNode(RectangleF bounds)
{
m_bounds = bounds;
}

//test se vuoto
public bool IsEmpty { get { return (m_bounds.IsEmpty || m_nodes.Count == 0) &amp;&amp; m_contents.Count==0; } }

//confini del nodo
public RectangleF Bounds { get { return m_bounds; } }

//contenuto del nodo
public List Contents { get { return m_contents; } }

//count degli item del nodo e dei subNodi
public int Count
{
get
{
int count = 0;

foreach (QuadTreeNode node in m_nodes)
count += node.Count;

count += this.Contents.Count;

return count;
}
}

//ritorna il contenuto globale di questo nodo(questo + subNodi)
public List FullContents
{
get
{
List results = new List();

foreach (QuadTreeNode node in m_nodes)
results.AddRange(node.FullContents);

results.AddRange(this.Contents);
return results;
}
}

//ritorna gli item all'interno di una certa area
public List Query(RectangleF queryArea)
{
List results = new List();

foreach (IQuadPoint item in this.Contents)
{
if (queryArea.Contains(item.Point))
results.Add(item);

}

foreach (QuadTreeNode node in m_nodes)
{
if (node.IsEmpty)
continue;

//se un subNodo contiente completamente la query area.. prendi tutto e esci
if (node.Bounds.Contains(queryArea))
{
results.AddRange(node.Query(queryArea));
break;
}

//se l'area contiene il subnodo, lo importa tutto e continua
if (queryArea.Contains(node.Bounds))
{
results.AddRange(node.FullContents);
continue;
}

//se il subnodo interseziona l'area di ricerca, allora inoltra la query ai suoi subNodi
if (node.Bounds.IntersectsWith(queryArea))
{
results.AddRange(node.Query(queryArea));
}

}

return results;

}

//inserisce un item
public void Insert(IQuadPoint item)
{
if (!m_bounds.Contains(item.Point))
{
//System.Diagnostics.Debug.Print("punto non compreso nel nodo:");
// System.Diagnostics.Debug.Print("---&gt;"+item.Point);

return;
}

//se c'e' capienza e non ho generato le foglie
if (this.Contents.Count &lt; maxElements &amp;&amp; m_nodes.Count ==0) { //inserisco in questo this.Contents.Add(item); return; } else { //genera i subtree if (m_nodes.Count == 0) { CreateSubNodes(); if (m_nodes.Count &gt; 0)
{
//ridistribuisco sui figli
foreach (IQuadPoint punto in Contents)
{
foreach (QuadTreeNode node in m_nodes)
{
if (node.Bounds.Contains(punto.Point))
{
node.Insert(punto);
break;
}
}
}

Contents.Clear();
}
else
{
//forza inserimento in questo nodo indipendentemente dalla size:
this.Contents.Add(item);
}
}

//per ogni subnodo fa l'add ricorsivo fino ad arrivare al quad piu piccolo
foreach (QuadTreeNode node in m_nodes)
{
if (node.Bounds.Contains(item.Point))
{
node.Insert(item);
return;
}
}

}

}

//solo in caso di paint
public void ForEach(QuadTree.QTAction action)
{
action(this);

// draw the child quads
foreach (QuadTreeNode node in this.m_nodes)
node.ForEach(action);
}

//Crea i subNodi
private void CreateSubNodes()
{
// the smallest subnode has an area
if ((m_bounds.Height * m_bounds.Width) return;

float halfWidth = (m_bounds.Width / 2f);
float halfHeight = (m_bounds.Height / 2f);

m_nodes.Add(new QuadTreeNode(new RectangleF(m_bounds.Location, new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode(new RectangleF(new PointF(m_bounds.Left, m_bounds.Top + halfHeight), new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode(new RectangleF(new PointF(m_bounds.Left + halfWidth, m_bounds.Top), new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode(new RectangleF(new PointF(m_bounds.Left + halfWidth, m_bounds.Top + halfHeight), new SizeF(halfWidth, halfHeight))));
}

}

Fatto cio è possibile usare il QuadTree e inserire i nostri oggetti.
Seguendo il progetto di Michael Coyle, ho realizzato un piccolo viewer per controllare il risultato e fare delle query di prova , il sistema è molto veloce in fase di inserimento (40000 punti inseriti in un secondo comprensivo di generazione di tutti i quad), e tempi di risposta in caso di interrogazione molto bassi, sotto il millisecondo.

Ovviamente per interrogare il quad, bisogna trasformare le coordinate geografiche in coordinate 2d piane.

Le formule di intersezione sono eseguite utilizzando le System.Drawing, beneficiando cosi della velocità delle librerie grafiche di windows.

 

Primi passi con C# e WCF : (3) WCF Service

In questo capitolo andiamo a definire la struttura del nostro WCF Service.

Abbiamo creato un webservice che fornice i dati dal backend. Ora dobbiamo creare uno strato isolato che permetta di interporsi tra il front end e il backend e isolare l’accesso ai dati e le dipendenze tra i due strati fondamentali.

In questo strato andiamo a definire un servizio wcf che esporrà i dati anagrafici e che utilizzerà un client soap per chiamare il webservice sottostante.

creiamo quindi nella solution precedente un altro progetto, di tipo WCF, Applicazione di servizi WCF:

Utilizziamo la funzione di refactoring per rinominare l’interfaccia del nostro servizio wcf, chiamandola IWCFAnagraficaService e rinominando il file cs in IWCFAnagraficaService.cs

Generalmente per creare un client verso un webservice, basta aggiungere il riferimento ad una risorsa web,e puntare al wsdl del webservice, e magicamente il tool di generazione, crea un proxy client completo.

Il Proxy nasce per rappresentare un contratto tra client e servizio, ma quando lo si genera in questa maniera, si rimane effettivamente legati ai tools, e alle loro problematiche .. WCF semplifica questo aspetto arrivando a definire un interfaccia di servizio che opportunatamente decorata da annotations e con gli attributi di serializzazione necessari, permette di chiamare in maniera trasparente il servizio.

Nessun tool di mezzo ed un codice molto pulito e manutenibile. Unico Drawback evidente, la necessità di dichiararci tutti gli oggetti che eseguono il binding con i risultati del webservice.

Andiamo quindi a creare una cartella dto in questo progetto .

Creiamo un DatiPersonaDto, con i dati che ci interessa esporre verso l’esterno ,un  IndirizzoDto e un DatiMovimentoDto, in modo da astrarci dal webservice sottostante ( e ragionare piu con un modello adatto alla fruizione indipendente dei dati).

Creiamo cosi i tre Dto :

IndirizzoDto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace WcfService1dto

{

public class IndirizzoDto

{

public int IdIndirizzo { get; set; }

public string TipoIndirizzo { get; set; }

public string Citta { get; set; }

public string Indirizzo { get; set; }

public string CAP { get; set; }

public string Provincia { get; set; }

}

}

DatiPersonaDto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace WcfService1dto

{

public class DatiPersonaDto

{

public int UserId { get; set; }

public string Nome { get; set; }

public string Cognome { get; set; }

public DateTime DataNascita { get; set; }

public IndirizzoDto[] Indirizzi { get; set; }

}

}

DatiMovimentoDto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace WcfService1dto

{

public class DatiMovimentoDto

{

public DateTime DataMovimento { get; set; }

public string Descrizione { get; set; }

public Double Valore { get; set; }

}

}

Ora che abbiamo definito i dati che verranno forniti da questo servizio, andiamo a definire le operationContract sull’interfaccia del servizio.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[ServiceContract]

public interface IWCFAnagraficaService

{

[OperationContract]

DatiPersonaDto getDatiAnagrafici(string username);

[OperationContract]

List<DatiMovimentoDto> getMovimentiPersona(string username);

}

Prima di passare all’implementazione del metodo nel servizio, andiamo a definire chi effettivamente eseguirà la chiamata al webservice. Definiamo un webserviceclient generico per il webservice creato in precedenza.

Utilizziamo Wcf anche per eseguire la connessione al webservice, realizzando un client senza andare a creare il webservice proxy , e quindi andando a definire anche in questo caso un interfaccia per il contratto tra client e service e decorarlo con le annotazioni necessarie.

Creiamo un folder webserviceclient nel nostro progetto e aggiungiamo un elemento di codice chiamato WebServiceSoapClient.cs

Utilizziamo in generics in modo da renderlo riusabile e indipendente. In questo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.Text;

public class WebServiceSoapClient<T> : IDisposable

{

private readonly T myChannel;

private readonly IClientChannel myClientChannel;

public WebServiceSoapClient(string url)

: this(url, null)

{

}

public WebServiceSoapClient(string url,

Action<CustomBinding, HttpTransportBindingElement, EndpointAddress, ChannelFactory> init)

{

//transport http o https

var transport = url.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)

? new HttpTransportBindingElement()

: new HttpsTransportBindingElement();

var binding = new CustomBinding();

//binding soap

binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8));

binding.Elements.Add(transport);

var address = new EndpointAddress(url);

//canale verso il webservice

var factory = new ChannelFactory<T>(binding, address);

if (init != null)

{

init(binding, transport, address, factory);

}

this.myClientChannel = (IClientChannel)factory.CreateChannel();

this.myChannel = (T)this.myClientChannel;

}

public void Dispose()

{

this.myClientChannel.Dispose();

}

public IClientChannel ClientChannel

{

get { return this.myClientChannel; }

}

public T Channel

{

get { return this.myChannel; }

}

}

L’oggetto appena creato ci permette di instanziare semplicemente un servizio utilizzando un interfaccia che ne descrive il contratto.

Quindi nel folder webserviceclient andiamo a creare gli oggetti per il binding dei tipi tornati dal webservice, e l’interfaccia per il servicecontract tra il nostro wcf e il webservice.

PersonaDto.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Runtime.Serialization;

using System;

[DataContract]

[Serializable]

public class PersonaDTO

{

[DataMember(IsRequired = true)]

public int UserId { get; set; }

public string Username { get; set; }

public string Nome { get; set; }

public string Cognome { get; set; }

public DateTime DataNascita { get; set; }

public string CittaResidenza { get; set; }

public string IndirizzoResidenza { get; set; }

public string CAPResidenza { get; set; }

public string ProvinciaResidenza { get; set; }

}

MovimentoDto.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Runtime.Serialization;

using System;

[DataContract]

[Serializable]

public class MovimentoDTO

{

[DataMember]

public int UserId { get; set; }

[DataMember]

public int IdMovimento { get; set; }

[DataMember]

public DateTime DataMovimento { get; set; }

[DataMember]

public string Descrizione { get; set; }

[DataMember]

public Double Valore { get; set; }

}

e l’interfaccia IAnagraficaInterface.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.ServiceModel;

namespace WcfService1.webserviceclient

{

[XmlSerializerFormat]

[ServiceContract(Namespace = "http://metalide.com/webservice1/")]

public interface IAnagraficaInterface

{

[OperationContract]

PersonaDTO getPersona(string username);

[OperationContract]

MovimentoDTO[] getMovimenti(int userid);

}

}

Ora che abbiamo definito tutte le nostre interfacce, andiamo ad implementare gli operationContract nell’implementazione del servizio nella classe WCFAnagraficaService

Utilizziamo un approccio thread safe nela definizione del client per il webservice in modo da riusarlo in maniera corretta

e implementiamo i due metodi del contratto, e l’ottenimento del canale di comunicazione tramite il client.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using System.Collections.Generic;

using WcfService1dto;

using WcfService1.webserviceclient;

namespace WcfService1

{

public class WCFAnagraficaService : IWCFAnagraficaService

{

//approccio thread safe

private static readonly object _synch = new object();

private static volatile WebServiceSoapClient<IAnagraficaInterface> webServiceClient;

public DatiPersonaDto GetDatiAnagrafici(string username)

{

var result1 = this.Channel.getPersona(username);

DatiPersonaDto dto = new DatiPersonaDto();

dto.UserId = result1.UserId;

dto.Cognome = result1.Cognome;

dto.Nome = result1.Nome;

dto.DataNascita = result1.DataNascita;

IndirizzoDto indirizzoDto = new IndirizzoDto();

indirizzoDto.IdIndirizzo = 1;

indirizzoDto.TipoIndirizzo = "residenza";

indirizzoDto.CAP = result1.CAPResidenza;

indirizzoDto.Citta = result1.CittaResidenza;

indirizzoDto.Indirizzo = result1.IndirizzoResidenza;

indirizzoDto.Provincia = result1.ProvinciaResidenza;

IndirizzoDto[] indirizzi = new IndirizzoDto[1];

indirizzi[0] = indirizzoDto;

dto.Indirizzi = indirizzi;

return dto;

}

public List<DatiMovimentoDto> GetMovimentiPersona(string username)

{

int userid = 1;

if (username.Equals("test"))

{

userid = 2;

}

var res = this.Channel.getMovimenti(userid);

List<DatiMovimentoDto> listaMovimenti = new List<DatiMovimentoDto>();

foreach (MovimentoDTO item in res)

{

DatiMovimentoDto dto = new DatiMovimentoDto();

dto.DataMovimento = item.DataMovimento;

dto.Descrizione = item.Descrizione;

dto.Valore = item.Valore;

listaMovimenti.Add(dto);

}

return listaMovimenti;

}

public IAnagraficaInterface Channel

{

get

{

if (webServiceClient == null)

{

lock (_synch)

{

if (webServiceClient == null)

{

webServiceClient = new WebServiceSoapClient<IAnagraficaInterface>(

@"http://localhost:4715/Service1.asmx");

}

}

}

return webServiceClient.Channel;

}

}

}

}

Se configuriamo la solution, in modo da avere progetti di avvio multipli, siamo in grado di eseguire il webservice in background, e testare il wcfservice tramite il client di test.

Eseguendo in debug, possiamo testare entrambi i metodi del nostro wcf service:

Scarica qui la solution completa