2010-10-01 10 views
29

J'écris actuellement une application de console C# qui génère un certain nombre d'URL qui pointent vers différentes images sur un site Web, puis les téléchargent en tant que flux d'octets en utilisant WebClient.DownloadDataAsync().Application de console terminée avant la fin de l'appel asynchrone

Mon problème est qu'une fois le premier appel asynchrone effectué, l'application console considère que le programme est terminé et se termine avant que l'appel asynchrone ne puisse retourner. En utilisant un Console.Read(), je peux forcer la console à rester ouverte mais cela ne semble pas très bon. De plus, si l'utilisateur frappe pendant le processus (alors que la console attend une entrée), le programme se terminera.

Y a-t-il un meilleur moyen d'empêcher la fermeture de la console pendant que j'attends qu'un appel asynchrone retourne?

Modifier: les appels sont asynchrones car je fournis un indicateur d'état via la console à l'utilisateur pendant le téléchargement.

Répondre

40

Oui. Utilisez un ManualResetEvent et appelez le rappel asynchrone event.Set(). Si la routine principale bloque sur event.WaitOne(), elle ne sortira pas tant que le code asynchrone n'aura pas été exécuté.

Le pseudo-code de base ressemblerait à ceci:

static ManualResetEvent resetEvent = new ManualResetEvent(false); 

static void Main() 
{ 
    CallAsyncMethod(); 
    resetEvent.WaitOne(); // Blocks until "set" 
} 

void DownloadDataCallback() 
{ 
    // Do your processing on completion... 

    resetEvent.Set(); // Allow the program to exit 
} 
+0

Merci! Cela a du sens et fonctionne parfaitement ... beaucoup mieux que console.read! – Andrew

+0

Je trouve également cela utile dans le débogage des services Windows en utilisant une 'tâche 'de longue durée en tant que travailleur principal. Dans 'Program.Main()', en utilisant une directive pré-processeur comme '# DEBUG [crochet de débogage] #else [code de service normal] # endif' Et puis dans le" crochet de débogage "je viens d'ajouter un appel à' resetEvent .WaitOne() 'après' new MyService(). OnStart() '. Ensuite, vous pouvez utiliser le débogage VS pour continuer à fonctionner en mode débogage sans modifier votre code de service réel de manière significative. –

+0

Vous êtes un génie freaking !! Je vous remercie! –

6

Si c'est tout ce que votre demande est en train de faire, je suggère de quitter le appel async; vous spécifiquement voulez l'application pour «se bloquer» jusqu'à ce que le téléchargement est terminé, donc en utilisant une opération asynchrone est contraire à ce que vous voulez ici, surtout dans une application de console.

+0

Je l'ai laissé dans mon explication de problème mais pendant le téléchargement j'affiche un indicateur de progrès à la fenêtre de console. Nous parlons de milliers d'images, il sera donc utile à l'utilisateur final de savoir ce qui se passe. – Andrew

+0

C'est bien; vous pouvez toujours mettre à jour la console à partir du même thread, aussi; l'utilisateur ne pourra tout simplement pas faire autre chose que Control-C, mais c'est le comportement que vous recherchez, de toute façon. –

+2

Utiliser async peut également être bénéfique si vous avez besoin de l'étendre pour télécharger plusieurs fichiers, etc ... n'était pas sûr de la logique ici, mais si c'est juste un fichier, synchrone serait plus facile .. –

18

Une autre option consiste simplement à appeler une méthode principale async et à attendre la tâche renvoyée.

static void Main(string[] args) 
{ 
    MainAsync(args).Wait(); 
} 

static async Task MainAsync(string[] args) 
{ 
    // .. code goes here 
} 

Depuis .NET 4.5, vous pouvez maintenant appeler GetAwaiter().GetResult()

static void Main(string[] args) 
{ 
    MainAsync(args).GetAwaiter().GetResult(); 
} 

What is the difference between .Wait() vs .GetAwaiter().GetResult()?

+2

Agréable et simple, exactement ce que je cherchais. –

Questions connexes