Imbriqué Try/Catch

est-ce qu'avoir un essai imbriqué/attraper un signal que vous ne codez pas proprement? Je me demande parce que dans mon catch j'appelle une autre méthode et si cela échoue j'obtiens une autre erreur d'exécution donc je suis tenté d'envelopper ces appels dans le catch avec un autre essai/catch à nouveau. Je me demande si c'est normal pour ce faire?

e.g.

    catch (Exception ex)
    {
        transaction.VoidOrder(transactionID);

        LogError(ex.ToString());
        Response.Redirect("Checkout", false);
    }

VoidOrder ou encore <!-Les méthodes pourraient exploser. Maintenant, quand je l'appelle VoidOrder, j'obtiens une valeur null réf sur transactionID parce qu'il appelle un BL méthode et dans cette méthode BL je lance à nouveau pour que je puisse l'attraper à ce niveau plus élevé dans le code ci-dessus. Mais si je jette à nouveau à l'intérieur d'une prise alors je dois attraper cela aussi.

18
demandé sur Phonon 2010-02-22 22:54:34

5 réponses

Voici comment nous abordons le problème:

tous les appels du niveau UI / codebehind vers d'autres niveaux utilisent un try-catch, où nous attrapons toujours une exception personnalisée. Toutes les actions prises par les couches sous-jacentes ont leur propre try-catch, qui log, envelopper et jeter l'exception personnalisée. L'UI peut alors se fier à cela et chercher des exceptions traitées avec des messages d'erreur conviviaux.

Code:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    //do something when a button is clicked...
    try
    {
        MyBL.TakeAction()
    }
    catch(MyApplicationCustomException ex)
    {
        //display something to the user, etc.
        ltlErrorPane.Text = ex.Message;

        //or redirect if desired
        if(ex.ErrorType == MyCustomErrorsType.Transactional)
        {
            Response.Redirect("~/Errors/Transaction.aspx");
        }
    }
}

BL:

Dans le couche d'affaires, toutes les opérations qui peuvent échouer utiliser un try-catch, qui enregistre et enveloppe la question avant de la jeter à L'UI.

public class MyBL
{
    public static void TakeAction()
    {
        try
        {
            //do something
        }
        catch(SpecificDotNetException ex)
        {
            //log, wrap and throw
            MyExceptionManagement.LogException(ex)
            throw new MyApplicationCustomException(ex, "Some friendly error message", MyCustomErrorsType.Transactional);
        }
        finally
        {
            //clean up...
        }
    }
}

gestionnaire d'Exception:

le gestionnaire d'exception actuel a plusieurs façons de se connecter, y compris le journal des événements, le journal des fichiers et enfin le courriel si tout le reste échoue. Nous choisissons de simplement retourner false si l'enregistreur ne peut pas faire l'une des actions attendues. IMO c'est un choix personnel. Nous pensons que la probabilité de 3 méthodes échouer dans la succession (le journal d'événement échoue, essayez le journal de fichier, échoue, essayez l'email, échoue) est très peu probable. Dans ce cas, nous avons choisi d'autoriser l'application à continuer. Votre autre option serait de permettre à l'application d'échouer complètement.

public static class MyExceptionManagement
{
    public static bool LogException(Exception ex)
    {
        try
        {
            //try logging to a log source by priority, 
            //if it fails with all sources, return false as a last resort
            //we choose not to let logging issues interfere with user experience

            //if logging worked
            return true;
        }
        catch(Exception ex)
        {
            //in most cases, using try-catch as a true-false is bad practice
            //but when logging an exception causes an exception itself, we do
            //use this as a well-considered choice.
            return false;
        }
    }
}

enfin, en tant que sécurité intégrée, nous mettons en œuvre le Application_Error gestionnaire d'événement global (en Global.asax). Ce est un dernier recours pour les cas où nous n'avons pas correctement essayez-attraper quelque chose. Nous nous connectons généralement et redirigeons vers une page d'erreur conviviale. Si le traitement d'erreur personnalisé ci-dessus est fait avec succès cependant, très peu d'erreurs le feront au gestionnaire global.

Espérons que cela pourrait aider un peu. C'est une solution possible. Il a très bien fonctionné pour nous depuis plusieurs années sur des applications importantes..

15
répondu KP. 2010-02-22 21:07:14

imbriqué try/catch les blocks sont inévitables dans les applications de haut niveau qui doivent enregistrer, envoyer des messages ou réagir aux exceptions de manière non triviale.

il y a des moyens de réduire le nombre de blocs imbriqués (par exemple, en consolidant la gestion des erreurs en utilisant ASP.NET ' s HttpApplication.Error handler (a. K. A. Application_Error)), mais vous devez attraper toutes les exceptions produites par votre code de manipulation et mettre en œuvre un plan de sauvegarde en cas d'échec de tout le reste.

5
répondu Jeff Sternal 2010-02-22 20:20:46

une autre solution à votre problème d'imbrication serait d'encapsuler la logique try / catch pour les fonctions internes (LogError, etc) dans ces fonctions, au lieu de dépendre de l'appelant pour les attraper. Pour LogError, cela aurait du sens parce que vous allez probablement vouloir gérer un logger d'erreur Cassé de la même manière, peu importe qui essaie de logger une erreur.

1
répondu Nick 2010-02-22 20:24:13

peut-être est-ce une question de savoir si quelqu'un peut comprendre pourquoi vous utilisez les try's/catches emboîtés. Parfois devient inévitable de les utiliser, mais je dis généralement n'est pas jolie.

Vous devriez considérer que la séparation des préoccupations est un must.

une méthode getControl ne doit pas y insérer de script, ni une méthode save ne doit faire plus que save.

examinez exactement ce que ces méthodes devraient faire et vous aurez votre réponse. Il n'a pas c'est gênant d'annuler un ordre en cas d'erreur. Semble raisonnable.

1
répondu marcelo-ferraz 2010-02-22 21:07:36

avez-vous songé à utiliser L'objet TransactionScope au lieu d'essayer de revenir en arrière manuellement? Je sais que parfois c'est impossible, mais la plupart du temps pour moi TransactionScope travaillé un régal. De cette façon, je n'ai pas eu à gérer les items roll back manuellement - les roll Back manuels pourraient être un problème de toute façon, parce que les données sont en quelque sorte dans un état "instable", ce qui pourrait gâcher toute votre logique.

0
répondu Wagner Silveira 2010-02-22 20:01:50