Domanda

La maggior parte del codice che ho scritto in .NET per effettuare chiamate REST sono stati sincrona. Dal momento che Silverlight su Windows Phone supporta solo asincrona WebClient e HttpWebRequest chiama, mi chiedevo cosa un buon modello asincrono è per una classe che espone i metodi che effettuano chiamate REST.

Per esempio, ho un app che ha bisogno di fare quanto segue.

  1. Login e ottenere gettone
  2. Utilizzo di token dal 1 #, ottenere un elenco degli album
  3. Uso gettone da 1 # ottenere un elenco di categorie
  4. etc

la mia classe espone alcuni metodi:

  1. Accesso ()
  2. GetAlbums ()
  3. GetCategories ()

dal momento che ogni metodo ha bisogno di chiamare WebClient utilizza chiamate asincrone quello che devo fare è essenzialmente blocco richiamante Accesso fino a che non ritorna in modo che io possa chiamare GetAlbums ().

Che cosa è un buon modo per andare su questo nella mia classe che espone questi metodi?

È stato utile?

Soluzione

Dipende da cosa si vuole fare con queste informazioni. Se per esempio si sta tentando di visualizzare l'elenco degli album / categorie, ecc, un modo per modellare questo sarebbe

  1. Avere una o più classi che implementa l'interfaccia INotifyPropertyChanged, e sono usati come fonti di dati per le vostre opinioni (guardare i file nella cartella di modelli in un nuovo PhoneListApplication per un esempio)
  2. Avvia un'operazione asincrona per accedere e ottenere il token, hanno negozio di callback del metodo asincrono il token per voi e per chiamare una funzione che inizierà un'operazione asincrona per ottenere l'elenco degli album e categorie.
  3. Il callback per l'operazione asincrona per ottenere un elenco di album / categorie possono aggiornare un ObservableList (con l'aggiunta di elementi ad esso). Mi piacerebbe di imaging si dispone di una classe ciascuna per gli album e categorie, ciascuna con una lista osservabile. In ogni modo, una volta che hai finito di aggiungere, basta chiamare NotifyPropertyChanged con il nome della proprietà è stato modificato, i dati dovrebbero presentarsi.

C'è un problema evidente con i casi in cui si desidera aspettare e non procedere fino a quando si riceve qualcosa in rete (per esempio se si desidera mantenere la pagina di login intorno finché non si sa che si è autenticato con successo). In questo caso si può solo cambiare la pagina nella callback asincrona.

È anche possibile che anche fare qualcosa di più elaborato e hanno un filo di attesa per un evento fissato dal callback asincrona. Vi consiglio di non avere il thread UI fare questo, in quanto limita la capacità di avere cose come timeout, ed è generalmente molto disordinato.

Altri suggerimenti

Si potrebbe dare un'occhiata al reattiva (Rx) estensioni quadro:

http://www.leading-edge-dev.de/?p = 501

http://themechanicalbride.blogspot.com /2009/07/introducing-rx-linq-to-events.html

[edit: ooh - trovato un buon link:] http://rxwiki.wikidot.com/101samples

Essi forniscono un modo per gli eventi "sequenza", che agiscono solo su determinate condizioni soddisfatte - per esempio, dire che si ha un metodo di "AuthenticationResult autenticazione (user stringa, passaggio string)"

Si potrebbe fare qualcosa di simile:

var foo = Observable.FromAsyncPattern<string, string, AuthenticationResult>
    (client.BeginAuthenticate, client.EndAuthenticate);
var bar = foo("username","password");
var result = bar.First();

efficace trasformando un metodo asincrono ad uno sincrona. È possibile estendere questo per includere "concatenamento":

var bar = foo("username", "password")
    .Then(authresult => DoSomethingWithResult(authresult));

roba pulita. :)

Abbiamo scritto il nostro livello di servizio sul lato client con tutte le firme di funzione asincrona che assomigliano a questo:

public void MyFunction(
  ArtType arg, 
  Action<ReturnType> success, 
  Action<FailureType> failure);

Il codice di servizio fa una chiamata asincrona al servizio Web, e quando che restituisce chiama la callback successo se la chiamata ha avuto successo, e la richiamata fallimento se ci fosse un guasto / eccezione. Poi il codice chiamante appare un po 'come questo:

MyServiceInstance.MyFunction(
  blahVar,
  returnVal => UIInvoker.Invoke(() => 
    {
      //some success code here
    }),
  fault => UIInvoker.Invoke(() => 
    {
      //some fault handling code here
    }));

(UIInvoker è solo un programma di utilità che invia di nuovo alla UI da un thread in background.)

ho messo insieme qualcosa che è un po 'più fluida.

riposante-Silverlight è una libreria che ho creato per aiutare sia con Silverlight e WP7.

codice

ho inserito qui sotto per mostrare come è possibile utilizzare la libreria per recuperare i tweet da Twitter.

Esempio Utilizzo di ristoratore-Silverlight tweet il recupero da Twitter:


//silverlight 4 usage
List<string> tweets = new List<string>();
var baseUri = "http://search.twitter.com/";

//new up asyncdelegation
var restFacilitator = new RestFacilitator();
var restService = new RestService(restFacilitator, baseUri);
var asyncDelegation = new AsyncDelegation(restFacilitator, restService, baseUri);

//tell async delegation to perform an HTTP/GET against a URI and return a dynamic type
asyncDelegation.Get<dynamic>(new { url = "search.json", q = "#haiku" })
    //when the HTTP/GET is performed, execute the following lambda against the result set.
    .WhenFinished(
    result => 
    {
        textBlockTweets.Text = "";
        //the json object returned by twitter contains a enumerable collection called results
        tweets = (result.results as IEnumerable).Select(s => s.text as string).ToList();
        foreach (string tweet in tweets)
        {
             textBlockTweets.Text += 
             HttpUtility.HtmlDecode(tweet) + 
             Environment.NewLine + 
             Environment.NewLine;
        }
    });

asyncDelegation.Go();

//wp7 usage
var baseUri = "http://search.twitter.com/";
var restFacilitator = new RestFacilitator();
var restService = new RestService(restFacilitator, baseUri);
var asyncDelegation = new AsyncDelegation(restFacilitator, restService, baseUri);

asyncDelegation.Get<Dictionary<string, object>>(new { url = "search.json", q = "#haiku" })
               .WhenFinished(
               result =>
               {
                   List<string> tweets = new List();
                   textBlockTweets.Text = "";
                   foreach (var tweetObject in result["results"].ToDictionaryArray())
                   {
                       textBlockTweets.Text +=
                           HttpUtility.HtmlDecode(tweetObject["text"].ToString()) + 
                           Environment.NewLine + 
                           Environment.NewLine;
                   }
               });

asyncDelegation.Go();

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top