web-dev-qa-db-fra.com

Erreur de capture lors de l'utilisation de Task.Factory

j'utilise ce qui suit

Task.Factory.StartNew(() => DoPrintConfigPage(serial));

alors la fonction que j'appelle ressemble à ceci

private void DoPrintConfigPage(string serial) 
{ 
    //do printing work 
}

Mon problème est qu'une exception est jetée à l'intérieur du fil et n'est pas traitée.

J'ai essayé de l'envelopper dans une prise d'essai

try
{
    Task.Factory.StartNew(() => DoPrintConfigPage(serial));
}
catch (Exception ex) { }

mais il ne capture toujours pas l'erreur et plante ainsi l'application.

Comment puis-je intercepter des exceptions dans le thread principal afin de pouvoir les gérer?

Mettre à jour

J'ai apporté les modifications recommandées ci-dessous et continue de dire que l'exception n'est pas gérée

var task =  Task.Factory.StartNew(() => DoPrintConfigPage(serial))
                               .ContinueWith(tsk =>
                               {
                                  MessageBox.Show("something broke");
                               },TaskContinuationOptions.OnlyOnFaulted);

puis dans ma DoConfigPage j'ai ajouté un autre essai de capture.

Dans cette capture est maintenant où il se bloque et en disant que l'exception en cours de lancement a été non gérée, ce qui me manque?

private void DoPrintConfigPage(string serial)
{
    try
    {
        //call the print function
    }
    catch (Exception ex)
    {
        throw ex;   //it is crashing here and saying it is unhandled
    }
}

J'ai aussi essayé ce que Eric J. a suggéré avec les mêmes résultats

var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial));

try
{
    task.Wait();                  
}
catch (AggregateException ex) { MessageBox.Show("something broke"); }
17
twaldron

Alternativement, vous pouvez chaîner la création de votre tâche et ajouter un ContinueWith:

var job = Task.Factory
    .StartNew(...)
    .ContinueWith(tsk => 
         {
              // check tsk for exception and handle
         });

EDIT: Cet extrait, lorsqu'il est exécuté, affiche la boîte de message pour moi:

void Main()
{
    var serial = "some serial";
    var task =  Task.Factory
        .StartNew(() => DoPrintConfigPage(serial))
        .ContinueWith(tsk =>
        {
            MessageBox.Show("something broke");
            var flattened = tsk.Exception.Flatten();

            // NOTE: Don't actually handle exceptions this way, m'kay?
            flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true;});
        },TaskContinuationOptions.OnlyOnFaulted);

}

public void DoPrintConfigPage(string serial)
{
    throw new Exception("BOOM!");
}
34
JerKimball

Votre bloc try est quitté immédiatement après le démarrage de la nouvelle tâche, car cette méthode continue de s'exécuter.

Au lieu de cela, vous pouvez intercepter l'exception en tant que AggregateException où vous attendez que la tâche (ou plusieurs tâches) se termine:

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("I'm bad, but not too bad!");
});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{
    // Assume we know what's going on with this particular exception. 
    // Rethrow anything else. AggregateException.Handle provides 
    // another way to express this. See later example. 
    foreach (var e in ae.InnerExceptions)
    {
        if (e is MyCustomException)
        {
            Console.WriteLine(e.Message);
        }
        else
        {
            throw;
        }
    }

}

http://msdn.Microsoft.com/en-us/library/dd997415.aspx

9
Eric J.

Si vous n'attendez pas votre tâche, je pense que la solution la plus simple se trouve dans Task.Exception :

Obtient l'exception AggregateException à l'origine de la fin prématurée de la tâche. Si la tâche s'est terminée avec succès ou n'a pas encore levé d'exception, la valeur null sera renvoyée.

J'utilise quelque chose comme ça:

Task.Factory.StartNew(() => DoStuffHere())
    .ContinueWith(task =>
    {
        if (task.Exception != null)
            Log("log all the exceptions!");
    });
7
sǝɯɐſ

Vous devez également connaître System.Threading.Tasks.TaskScheduler.UnobservedTaskException .

Si vous créez des instances Task "lancez et oubliez", vous voudrez vous abonner à cet événement au début de votre programme.

3
Timothy Shields

Peut-être essayez-vous d'attraper une exception d'état corrompu . Étant donné que les applications .NET 4 ne peuvent pas intercepter ces exceptions par défaut. Vous pouvez essayer d’ajouter l’entrée legacyCorruptedState­­ExceptionsPolicy=true à votre fichier de configuration comme indiqué dans l’article MSDN lié ci-dessus.

0
MiGro