A quale livello appartiene il codice asincrono?

4

Sto sviluppando un'applicazione che consuma dati da un servizio esterno. L'applicazione viene implementata seguendo una tipica architettura a più livelli con livelli di interfaccia utente, presentazione, dominio e dati. Il client del servizio risiede nel livello dati.

Come in genere, non voglio che l'interfaccia utente si "blocchi" mentre si attende il completamento delle chiamate dal servizio esterno. Tuttavia, l'implementazione degli agenti di servizio con metodi asincroni genera un modello complicato che concatena i metodi asincroni dei livelli in modo che l'interfaccia utente possa rimanere reattiva.

Ad esempio:

Nel ViewModel:

TheRepository.LoadDataAsync().ContinueWith(t => { _data = t.Result; });

In TheRepository:

public Task<TheData> LoadDataAsync()
{
    return ServiceClient.GetDataFromServiceAsync();
}

(Nota, questa è una significativa semplificazione eccessiva intesa a trasmettere ciò che intendo per concatenazione di attività.)

Poiché il requisito è un requisito dell'interfaccia utente (impedisce all'interfaccia utente di "bloccare"), non ha senso mantenere i livelli Dominio e Dati in modo sincrono e lasciarlo al livello Presentazione per decidere quando è necessario eseguire alcuni operazione in modo asincrono?

D'altra parte, è molto semplice e naturale implementare il servizio client / proxy con metodi asincroni (VS li auto-genererà se necessario) perché questo è ciò che pensiamo quando pensiamo alla necessità di async.

Se l'applicazione estraeva i dati da un database invece di effettuare una chiamata di servizio, i livelli non sarebbero diversi e non dovrebbe davvero cambiare il modo in cui sono stati implementati i livelli dell'interfaccia utente, della presentazione o del dominio, giusto? In questo caso, non ci penseremmo due volte a fare in modo che l'accesso ai dati sia sincrono.

Sarebbe un progetto migliore modellare il Dominio in modo sincrono e lasciarlo al livello Presentazione per risolvere i problemi di prestazioni nell'interfaccia utente? Oppure, nel mondo emergente asincrono, dovremmo semplicemente accettare asincrono come norma e fare in modo che tutto si adatti a questo modello?

    
posta SonOfPirate 02.08.2013 - 19:37
fonte

3 risposte

5

Se un componente funziona in modo sincrono o asincrono è un dettaglio di implementazione. La scelta di design per ogni livello dovrebbe essere indipendente.

Hai dichiarato un caso d'uso in cui il livello dell'interfaccia utente è asincrono, non deve essere bloccato in modo che sia asincrono. Per ogni altro livello se hanno un caso d'uso per essere asincroni, rendili asincroni, altrimenti rendili sincroni. Come lo descrivi attualmente, non vedo alcun vantaggio nell'avere il tuo repository asincrono.

    
risposta data 02.09.2013 - 12:43
fonte
1
 > Which layer does async code belong?

Risposta breve: in presenter o in un extra livello di servizio ma non nel livello gui, data o dominio.

Risposta lunga:

Lo inserirò in un livello di servizio che si trova tra il livello del presentatore e del dominio risultante in questi livelli

gui - presenter - service - domain - data

Nel domainlayer (o servicelayer) si ha una versione sincronizzata della logica che deve consumare i dati del servizio esterno. Lo chiamo mySyncMethod .

Nel servicelayer crei un sottile involucro asincrono attorno a mySyncMethod .

Motivo: è molto difficile separare i metodi asincroni. i metodi di sincronizzazione sono molto più facili da testare.

Se c'è un solo riferimento alla funzionalità asincrona che puoi inserire nel presentatore.

    
risposta data 03.08.2013 - 10:14
fonte
0

Ogni volta che gestisco le chiamate web asincrone che popolano i dati dell'interfaccia utente, avvio lanciando un indicatore occupato di qualche tipo (a meno che non si tratti di qualcosa che l'utente finale non sta specificatamente aspettando che accada). Una volta che i dati sono pronti, lo inserisco in una proprietà che viene sincronizzata con l'interfaccia utente sul successivo loop del thread dell'interfaccia utente o esegue il marshalling di un messaggio sul thread dell'interfaccia utente a seconda del tipo di applicazione e della piattaforma su cui sto sviluppando. Ecco un esempio rapido e sporco in C # :

// Method executed in some other non UI thread!
private void OtherThreadMethod() {
    //Invoke the method that should change the control in the UI thread
    this.Dispatcher.BeginInvoke( UIThreadMethod );
}

private void UIThreadMethod() {
    //Perform the change of the control
    this.Cursor = Cursors.Wait;
}

L'obiettivo è che se l'utente è in attesa che qualcosa accada o che alcuni dati in background debbano essere gestiti, il programma non dovrebbe semplicemente bloccarsi e attendere. Per esempio se sto copiando un file in Windows Explorer, voglio poter sfogliare le mie foto mentre aspetto.

    
risposta data 02.08.2013 - 21:06
fonte