Question

Mon application WinForms utilise plusieurs BackgroundWorker . objets pour récupérer des informations d'une base de données. J'utilise BackgroundWorker parce que cela permet à l'interface utilisateur de rester débloquée lors de requêtes de base de données longues et simplifie le modèle de threading pour moi.

Je reçois occasionnellement des exceptions DatabaseException dans certains de ces threads d'arrière-plan et j'ai été témoin d'au moins une de ces exceptions dans un thread de travail lors du débogage. Je suis assez confiant que ces exceptions sont des délais d'attente auxquels je suppose qu'il est raisonnable de s'attendre de temps en temps.

Ma question concerne ce qui se passe lorsqu'une exception non gérée se produit dans l'un de ces threads de travail en arrière-plan.

Je ne pense pas que je puisse intercepter une exception dans un autre thread, mais puis-je m'attendre à ce que ma méthode WorkerCompleted soit exécutée? Existe-t-il une propriété ou une méthode de BackgroundWorker que je peux interroger à la recherche d’exceptions?

Était-ce utile?

La solution

Si l'opération déclenche une exception que votre code ne gère pas, le BackgroundWorker capture l'exception et la transmet au gestionnaire d'événements RunWorkerCompleted , où elle est exposée en tant que Propriété d'erreur de System.ComponentModel.RunWorkerCompletedEventArgs . Si vous exécutez le débogueur Visual Studio, celui-ci sera interrompu au point du gestionnaire d'événements DoWork où l'exception non gérée a été déclenchée.

http://msdn.microsoft.com/ en-us / library / system.componentmodel.backgroundworker.dowork.aspx

Autres conseils

J'utilise pleinement BackgroundWorker depuis plusieurs années et je le connais vraiment en profondeur.

Récemment, mon RunWorkerCompleted n'intercepte pas le e.Error lorsque je lance simplement une nouvelle exception (" Test &); dans < code> DoWork . Cependant, exception non gérée levée. La capture dans DoWork n'est pas la meilleure pratique. Par conséquent, e.Error n'a pas de sens.

Lorsque j'essaie de créer un nouveau Form avec le nouveau BackgroundWorker , e.Error dans RunWorkerCompleted a été géré avec succès. Il devrait y avoir quelque chose qui cloche dans mon BackgroundWorker compliqué.

Après quelques jours à googler et à déboguer, essayez une erreur. J'ai trouvé cela dans mon RunWorkerCompleted :

  • Vérifiez d'abord e.Error , puis e.Cancelled et enfin e.Result
  • Ne pas obtenir le e.Result si e.Cancelled = True .
  • Ne pas obtenir le e.Result si e.Error n'est pas null (ou rien ) * *

** C'est ici que je manque. Si vous essayez d'utiliser e.Result si e.Error n'est pas null (ou rien ), exception gérée sera jeté.

MISE À JOUR: Dans la propriété e.Result get .NET, concevez-le pour vérifier e.Error en premier. En cas d'erreur, ils renverront la même exception à partir de DoWork . C’est la raison pour laquelle nous obtenons une exception non gérée dans RunWorkerCompleted , mais en réalité l’exception provient de DoWork .

Voici la meilleure pratique à suivre dans RunWorkerCompleted :

If e.Error IsNot Nothing Then
  ' Handle the error here
Else
  If e.Cancelled Then
    ' Tell user the process canceled here
  Else
    ' Tell user the process completed
    ' and you can use e.Result only here.
  End If
End If

Si vous souhaitez un objet accessible à tous DoWork, ProgressChanged et RunWorkerCompleted, utilisez la méthode suivante:

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)

Vous pouvez facilement accéder à ThreadInfos (expéditeur) .Field où vous voulez.

Par défaut, il sera capturé et stocké par BackgroundWorker. À partir de MSDN:

  

Si l'opération génère une exception que votre code ne gère pas, BackgroundWorker capture l'exception et la transmet au gestionnaire d'événements RunWorkerCompleted, où elle est exposée en tant que propriété Error de System.ComponentModel.RunWorkerCompletedEventArgs. Si vous exécutez le débogueur Visual Studio, celui-ci sera interrompu au point du gestionnaire d'événements DoWork où l'exception non gérée a été déclenchée.

Comme cela a déjà été noté:

  

Si l'opération déclenche une exception   que votre code ne gère pas, le   BackgroundWorker intercepte l'exception   et le passe dans le   Gestionnaire d'événements RunWorkerCompleted,   où il est exposé comme erreur   propriété de   System.ComponentModel.RunWorkerCompletedEventArgs.

Ceci est important lorsque vous interagissez avec le fil de discussion d'origine. Par exemple, si vous souhaitez que le résultat de votre exception soit écrit dans une sorte d'étiquette sur votre formulaire, vous ne devez pas intercepter l'exception dans DoWork de BackgroundWorker, mais gérer e.Error à partir de RunWorkerCompletedEventArgs.

Si vous analysez le code BackgroundWorker avec un réflecteur, vous verrez qu'il est très simple à gérer: Votre DoWork est exécuté dans un bloc try-catch et l'exception est simplement transmise à RunWorkerCompleted. C’est la raison pour laquelle je ne suis pas d’accord avec la méthode «préférée» consistant à toujours intercepter toutes vos exceptions dans l’événement DoWork.

En bref, pour répondre à la question initiale:

Oui , vous pouvez compter sur votre RunWorkerCompleted pour toujours être renvoyé.

Utilisez e.Error dans RunWorkerCompleted pour rechercher des exceptions dans l'autre thread.

Ceci fonctionnera uniquement sans le débogueur attaché. Lorsqu'il sera exécuté à partir de Visual Studio, il détectera l'exception non gérée dans la méthode DoWork et interrompra l'exécution. Toutefois, vous pourrez cliquer sur Continuer et RunWorkerCompleted sera atteint et vous pourrez lire exception via le champ e.Error.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top