2010-03-23 5 views
1

J'ai une classe qui stocke essentiellement les fichiers dans amazon s3. Voici à quoi il ressemble (simplifié)Appel d'un void asynchrone. - Modèle basé sur un événement, ou une autre méthode?

public class S3FileStore 
{ 
    public void PutFile(string ID, Stream content) 
     { 
      //do stuff 
     } 
} 

Dans mon application client, je veux être en mesure d'appeler:

var s3 = new() S3FileStore(); 
s3.PutFile ("myId", File.OpenRead(@"C:\myFile1")); 
s3.PutFile ("myId", File.OpenRead(@"C:\myFile2")); 
s3.PutFile ("myId", File.OpenRead(@"C:\myFile3")); 

Je veux que ce soit une opération asynchrone - Je veux que le S3FileStore pour gérer cela (je ne veux pas que mon appelant doive exécuter de manière asynchrone PutFile pour ainsi dire) mais, je veux être capable de piéger des exceptions/dire si l'opération s'est terminée pour chaque fichier.

J'ai regardé des appels async à base d'événements, en particulier ceci: http://blogs.windowsclient.net/rendle/archive/2008/11/04/functional-shortcuts-2-event-based-asynchronous-pattern.aspx

Cependant, je ne vois pas comment appeler ma méthode PutFile (vide)?

Y a-t-il de meilleurs exemples?

Répondre

1

La classe de base BackgroundWorker pourrait être intéressant de regarder, et aussi le fil Piscine:

ThreadPool.QueueUserWorkItem(delegate 
    { 
     s3.PutFile ("myId", File.OpenRead(@"C:\myFile1")); 
    }); 

Ceci est essentiellement ce que vous feriez avec l'action/motif BeginInvoke. Avec BeginInvoke, vous recevez en plus un IAsyncResult sur lequel vous pouvez appeler .WaitOne() pour bloquer le thread en cours jusqu'à la fin de l'opération, au cas où vous en auriez besoin. Vous devez déclencher un nouveau BeginInvoke pour chaque fichier que vous souhaitez enregistrer.

Si vous devez le faire souvent, une version plus sophistiquée pourrait être d'utiliser une file d'attente en combinaison avec le BackgroundWorker, .: par exemple

public sealed class S3StoreLikePutFileWorker<TYourData> : BackgroundWorker 
{ 
    private AutoResetEvent WakeUpEvent = new AutoResetEvent(false); 

    private Queue<TYourData> DataQueue = new Queue<TYourData>(); 

    private volatile bool StopWork = false; 

    public void PutFile(TYourData dataToWrite) 
    { 
     DataQueue.Enqueue(dataToWrite); 
     WakeUpEvent.Set(); 
    } 

    public void Close() 
    { 
     StopWork = true; 
     WakeUpEvent.Set(); 
    } 

    private override void OnDoWork(DoWorkEventArgs e) 
    { 
     do 
     { 
      // sleep until there is something to do 
      WakeUpEvent.WaitOne(); 
      if(StopWork) break; 

      // Write data, if available 
      while(DataQueue.Count > 0) 
      { 
       TYourData yourDataToWrite = DataQueue.Dequeue(); 
       // write data to file 
      } 
     } 
     while(!StopWork); 
    } 
} 

Selon la quantité de complexité dont vous avez besoin.

Le BackgroundWorker prend en charge les commentaires des progrès (mis WorkerReportsProgress = true; dans le constructeur), et vous pouvez également ajouter un événement personnalisé pour signaler les erreurs, si cela est nécessaire:

// create a custom EventArgs class that provides the information you need 
public sealed class MyEventArgs : EventArgs { 
    // Add information about the file 
} 

// ... define the event in the worker class ... 
public event EventHandler<MyEventArgs> ErrorOccured; 

// ... call it in the worker class (if needed) ... 
if(ErrorOccured != null) ErrorOccured(this, new MyEventArgs(/*...*/)); 

Questions connexes