2010-04-10 7 views
7

Quando si richiama un servizio WCF in modo asincrono, sembra che ci siano due modi per farlo.Quale modo si preferisce quando si eseguono chiamate WCF asincrone?

1.

WcfClient _client = new WcfClient();  
public void One() 
{ 
    _client.BegindoSearch("input", ResultOne, null); 
} 

private void ResultOne(IAsyncResult ar) 
{ 
    string data = _client.EnddoSearch(ar); 
} 

2.

public void Two() 
{ 
    WcfClient client = new WcfClient(); 
    client.doSearchCompleted += TwoCompleted; 
    client.doSearchAsync("input"); 
} 

void TwoCompleted(object sender, doSearchCompletedEventArgs e) 
{ 
    string data = e.Result; 
} 

E con la nuova classe Task<T> abbiamo un terzo modo semplice avvolgendo il sincronismo in un compito.

3.

public void Three() 
{ 
    WcfClient client = new WcfClient(); 
    var task = Task<string>.Factory.StartNew(() => client.doSearch("input")); 
    string data = task.Result; 
} 

Tutti gli danno la possibilità di eseguire altro codice, mentre si attende per il risultato, ma penso che Task<T> dà maggiore controllo su ciò che si esegue prima o dopo il risultato viene recuperato .

Ci sono vantaggi o svantaggi nell'usare l'uno sull'altro? O scenari in cui un modo per farlo è più preferibile?

risposta

5

Vorrei non utilizzare la versione finale perché eseguirà l'operazione su un thread di lavoro anziché un thread di I/O. Ciò è particolarmente grave se lo stai facendo all'interno di ASP.NET, dove i thread di lavoro sono necessari per servire le richieste. Per non parlare, stai ancora bloccando il thread principale in attesa che l'attività termini quando controlli il suo Result, quindi tecnicamente stai sprecando due thread di lavoro o un lavoratore e l'interfaccia utente.

I metodi BeginXYZ e XyzAsync per i client WCF funzionano essenzialmente allo stesso modo: è necessario scegliere la versione appropriata in base al caso d'uso che si desidera supportare (rispettivamente, APC o event-driven). Ad esempio, la versione BeginXyz sarebbe (forse controintuitivamente) più facile da utilizzare all'interno di una pagina asincrona ASP.NET (o MVC), mentre la versione XyzAsync sarebbe più semplice da utilizzare in un Windows Form.

+0

L'aspetto del filo Worker vs IO è interessante. So che il pool di thread ha una quantità fissa di ciascuno e che è possibile cambiarli. Ma qual è la differenza tra un thread di lavoro e un thread di I/O nel framework. Presumo che sia più che una semantica. –

+0

@ Mikael: I thread I/O sono progettati per lunghi periodi di attesa; in pratica vanno a dormire e aspettano che il sistema I/O li riattivi con un'interruzione. I thread di lavoro sono pensati per il lavoro pesante della CPU e non si vuole sprecarli per bloccare le chiamate I/O sincrone. – Aaronaught

+0

ci sono ulteriori informazioni in questo articolo di MSDN sulle attività relative ai thread di lavoro - http://msdn.microsoft.com/en-us/magazine/ff959203.aspx - anche un buon background (una sorta di lezione di storia) sul diversi metodi asincroni disponibili in.NET –

2

C'è un problema con il primo esempio. Si dovrebbe certamente non creare una nuova istanza WcfClient quando si chiama EndDoSearch. È necessario mantenere l'istanza originale in un campo o passarla come parametro di stato.

In generale, preferisco l'opzione n. 1 perché rende molto semplice l'utilizzo di un metodo anonimo per gestire il risultato.

var client = new WcfClient(); 
client.BeginDoSearch("input", ar => { 

    var result = client.EndDoSearch(ar); 
    // blah blah 

}, null); 
+0

Buona presa su quello; badate bene, è difficile creare clienti WCF al volo * periodo * - di solito questi finiscono per essere singletons/per-session o gestiti da un contenitore DI. – Aaronaught

+0

@Josh, so che dovrei usare lo stesso client e lo ho corretto ora :) –