Question

J'ai une petite application WinForms qui utilise un objet BackgroundWorker pour effectuer une opération de longue durée.

L'opération en arrière-plan génère des exceptions occasionnelles, généralement lorsqu'un utilisateur ouvre un fichier en cours de recréation.

Que le code soit exécuté à partir de l'EDI ou non, .NET affiche une boîte de dialogue d'erreur informant l'utilisateur qu'une exception non gérée s'est produite. Compiler le code à l’aide de la configuration Release ne change rien à cela.

Selon 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.

Je m'attends à ce que ces exceptions soient levées à l'occasion et souhaiterais les gérer dans l'événement RunWorkerCompleted plutôt que dans DoWork. Mon code fonctionne correctement et l'erreur est gérée correctement dans l'événement RunWorkerCompleted, mais je ne peux pas comprendre comment arrêter le dialogue d'erreur .NET en se plaignant de & "Exception non gérée &"; de se produire.

BackgroundWorker n'est-il pas censé détecter cette erreur automatiquement? N'est-ce pas ce que dit la documentation MSDN? Que dois-je faire pour informer .NET que cette erreur est gérée tout en permettant à l’exception de se propager dans la propriété Error de RunWorkerCompletedEventArgs?

Était-ce utile?

La solution

Ce que vous décrivez n'est pas le comportement défini de BackgroundWorker. Je suppose que vous faites quelque chose de mal.

Voici un petit exemple qui prouve que BackgroundWorker mange des exceptions dans DoWork et les met à votre disposition dans RunWorkerCompleted :

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

Mes compétences en débogage psychique me révèlent votre problème: vous accédez à e.Result dans votre gestionnaire RunWorkerCompleted - s'il existe une e.Error, vous devez la gérer sans accéder à e.Result. Par exemple, le code suivant est mauvais, mauvais, mauvais et lève une exception lors de l'exécution:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

Voici une implémentation appropriée du gestionnaire d'événements RunWorkerCompleted:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

VOILA, vous ne recevrez pas d'exceptions d'exécution.

Autres conseils

J'ajouterais au Texte 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 à l'endroit du gestionnaire d'événements DoWork où l'exception non gérée a été déclenchée.

... ET le débogueur signalera l'exception comme & "; ~ L'exception n'a pas été gérée par le code utilisateur &";

.

Solution: N'exécutez pas le programme de mise au point et tout fonctionnera comme prévu: exception interceptée dans e.Error.

C’est une vieille question, mais je l’ai trouvée en recherchant les mêmes symptômes sur Google. Publier ceci au cas où quelqu'un d'autre le trouverait pour la même raison.

La réponse de Judah est correcte, mais ce n’est pas la seule raison pour laquelle & «exception non gérée dans le code utilisateur &»; dialogue peut apparaître. Si une exception est levée à partir d'un constructeur sur le thread d'arrière-plan, cette exception entraînera le dialogue immédiatement et ne sera pas transmise à l'événement RunWorkerCompleted. Si vous déplacez le code incriminé en dehors de tout constructeur (vers toute autre méthode), il fonctionnera comme prévu.

[Modifier]

Judah a un très bon point. Mon exemple a souligné les spécificités de la gestion de l'erreur, mais mon code provoquerait en réalité une autre exception si une exception n'était jamais touchée dans la méthode DoWork. Cet exemple est OK car nous montrons spécifiquement les capacités de traitement des erreurs de BackgroundWorker. Toutefois, si vous ne comparez pas le paramètre error avec la valeur null, cela pourrait être votre problème.

[/ Edit]

Je ne vois pas les mêmes résultats. Pouvez-vous poster un petit code? Voici mon code.

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

Sortie du programme:

  

Erreur? System.Exception: BOOM à   BackgroundException.Form1.worker_DoWork (Object   l'expéditeur, DoWorkEventArgs e) in   D: \ Workspaces \ Sandbox \ BackgroundException \ BackgroundException \ Form1.cs: line   43 à   System.ComponentModel.BackgroundWorker.OnDoWork (DoWorkEventArgs   e) à   System.ComponentModel.BackgroundWorker.WorkerThreadStart (Object   argument)

Un article intéressant qui ressemble à votre question. Il comporte une section sur la gestion des exceptions.

http://www.developerdotstar.com/community/node/671

J'ai eu le même problème et j'appliquais déjà la réponse de Judah avant de trouver ce sujet après une recherche sur Google.

Eh bien, la réponse de Judah est partiellement correcte. J'ai trouvé une meilleure réponse ici

Le débogueur fait le travail correctement, si vous exécutez l'application dans & "Conditions du monde réel &", RunWorkerCompleted gère l'exception comme prévu et le comportement de l'application est également le comportement attendu.

J'espère que cette réponse vous aidera.

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