【问题标题】:how to: handle exceptions, best practices如何:处理异常、最佳实践
【发布时间】:2010-05-29 10:11:50
【问题描述】:

需要实现全局错误处理,所以也许你可以用下面的例子来帮忙......

我有这个代码:

public bool IsUserAuthorizedToSignIn(string userEMailAddress, string userPassword)
        {
            // get MD5 hash for use in the LINQ query
            string passwordSaltedHash = this.PasswordSaltedHash(userEMailAddress, userPassword);

            // check for email / password / validity
            using (UserManagementDataContext context = new UserManagementDataContext())
            {
                var users = from u in context.Users
                            where u.UserEMailAdresses.Any(e => e.EMailAddress == userEMailAddress)
                                && u.UserPasswords.Any(p => p.PasswordSaltedHash == passwordSaltedHash)
                                && u.IsActive == true
                            select u;

                // true if user found
                return (users.Count() == 1) ? true : false;
            }
        }

还有 md5:

private string PasswordSaltedHash(string userEMailAddress, string userPassword)
        {
            MD5 hasher = MD5.Create();
            byte[] data = hasher.ComputeHash(Encoding.Default.GetBytes(userPassword + userEMailAddress));

            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                stringBuilder.Append(data[i].ToString("x2"));
            }

            Trace.WriteLine(String.Empty);
            Trace.WriteLine("hash: " + stringBuilder.ToString());
            return stringBuilder.ToString();
        }

那么,我将如何处理这些函数的异常?他们第一个是从 Default.aspx 页面调用的。第二个仅从类库中的其他函数调用。

最佳做法是什么?

  • 每个函数内的环绕代码try-catch
  • try-catch包围函数调用
  • 还有别的吗??

如果发生异常怎么办?

在这个例子中: 这是一个用户登录,所以即使一切都失败了,用户也应该得到一些有意义的信息 - 大致如下:登录正常(只是重定向),登录不正常(错误的用户名/密码),登录不可能由于内部问题,抱歉(发生异常)。

对于第一个函数,我担心数据库访问是否存在问题。 不知道第二个是否有什么需要处理的。

谢谢你的信息。你会怎么做? 需要这方面的具体信息(我更容易理解),还需要有关如何处理其他任务/功能的一般信息。

我浏览了互联网,但每个人都有不同的话要说,所以不确定该怎么做...将在这里获得最多票数,或者最合乎逻辑的答案:) 谢谢。

【问题讨论】:

    标签: c# asp.net exception exception-handling


    【解决方案1】:

    两条黄金法则:

    1. 如果方法无法按照其名称执行的操作,则引发异常。
    2. 除非您确切知道如何处理异常,否则不要捕获异常。

    请记住,异常表明出现了问题,而特定的事情可能与您的想法不同。 (内存不足、堆栈溢出、第 3 方服务中断、部署错误导致程序集丢失、配置错误、安全异常等)。

    除了极少数异常,您应该看到 Pokemon 异常处理的唯一位置是在代码的最顶层,异常应该在某处发布。例如,在 global.asax 文件中的 Application_Error 方法中。

    以下是一些对您有帮助的链接:

    【讨论】:

    • 呵呵,不错的黄金法则。非常合乎逻辑。 :)
    【解决方案2】:

    您的图书馆代码或代码 由您的更高层使用 应用程序必须始终只抛出 例外,从不担心如何 对付他们。

    这很重要,因为您可以在许多地方出于不同目的使用此库。

    在您的应用程序表示层中,如果您正在使用库代码并且您知道可能的异常,那么请使用 try/catch 捕获它们。

    由于您使用的是 asp.net,我建议您编写一个通用的页面基类,并在 Page_Error 事件中使用一些错误处理机制来捕获页面上所有未处理的异常。

    除此之外,您甚至可以在 global.asax 中使用Application_Error 来捕获应用程序、模块、处理程序、服务、页面等任何部分中的任何未处理的异常。

    我强烈建议不要这样做 处理所有问题的一般做法 全局 Application_Error 异常。

    【讨论】:

    • 哇,这似乎是一个很棒的建议。我喜欢处理这些库函数之外的错误的想法,因为我确实想尽可能地重用它们(库函数)。也喜欢针对未处理错误的 Page_Error 事件建议和针对所有其他错误的 Application_Error。
    • 你明白了。 .Net 框架库还会在框架无法执行任何操作或不知道如何处理的情况下引发异常。它只是抛出异常。 That's the whole idea of having exceptions. 如果您不知道如何处理给定上下文中的错误,只需抛出异常并可能在正确的上下文中捕获它。
    • 我认为使用框架作为异常处理模型是个好主意。当异常通过框架中的层时,该框架还会转换异常,因为方法中的合同发生变化。我认为,如果您有业务逻辑和数据访问层,那么 UI 层就没有理由知道诸如 SqlExceptions 之类的事情。异常应该用调用方法的层的语言来描述。
    【解决方案3】:

    您需要考虑方法定义的契约。如果一个方法不能履行它的契约,那么你需要一个例外。方法中抛出的异常应该被翻译成从方法契约的角度来看是有意义的异常。

    在第一种情况下,我会捕获语句执行可能引发的任何异常(例如数据库错误)并将它们转换为类似 AuthorisationException 的东西。从方法契约的角度来看,允许异常直接传播是没有意义的。例如,当方法履行作者是否被授权的合同时,允许数据库异常从方法中逃逸是没有意义的。

    将这种方法的想法用作合同可以让您做出正确的决定。如果一个方法契约正在登录数据库,或者一些数据库操作,那么允许异常传播可能是有意义的。

    具体化:使用第一个示例:

    public bool IsUserAuthorizedToSignIn(string userEMailAddress, string userPassword)
        {
            try
            {
                // get MD5 hash for use in the LINQ query
                string passwordSaltedHash = this.PasswordSaltedHash(userEMailAddress, userPassword);
    
                // check for email / password / validity
                using (UserManagementDataContext context = new UserManagementDataContext())
                {
                    var users = from u in context.Users
                            where u.UserEMailAdresses.Any(e => e.EMailAddress == userEMailAddress)
                                && u.UserPasswords.Any(p => p.PasswordSaltedHash == passwordSaltedHash)
                                && u.IsActive == true
                            select u;
    
                    // true if user found
                    return (users.Count() == 1) ? true : false;
                }
            }
            catch(ThisException e)
            {
                thrown new AuthorisationException("Problem1 occurred");
            }
            catch(ThatException e)
            {
                thrown new AuthorisationException("Problem2 occurred");
            }
            catch(OtherException e)
            {
                thrown new AuthorisationException("Problem3 occurred");
            }
        }
    

    您可能还想在 AuthorisationException 上设置内部异常:

            catch(ThisException e)
            {
                thrown new AuthorisationException("Problem1 occurred", e);
            }
    

    那么你的客户端代码可以这样做:

    try
    {
        if(User.IsUserAuthorizedToSignIn)
        {
            // Let the magic happen
        }
        else
        {
            // No rights
        }
    }
    catch(AuthorisationException e)
    {
        // Let the user know there is something up with the system. 
    }
    

    您可能决定不想在直接调用站点捕获 AuthorisationException,因为您无法通知用户。所以你可以让它传播到你可以用它做某事的水平。

    希望有帮助!

    【讨论】:

    • 是的,我喜欢 AuthorisationException,因为那时我只需要处理 AuthorisationException 案例,而不是未知事物的列表 - 它们会卡在 OTHER 中。
    • 非常正确,我只是想在制作茶杯时添加这一点。从客户端站点来看,代码看起来更简洁,并且专注于客户端试图实现的目标,而不是如何实现。
    • 很遗憾,现有的异常机制和层次结构并不能更好地通过“异常以何种方式不满足其预期条件,并且必须在来电者满足其后置条件?”这确实是一个 50,000 美元的问题,在决定是否应该捕获并吞下、捕获并包装、捕获并重新抛出异常或不捕获异常时需要提出这个问题。
    猜你喜欢
    • 2018-01-03
    • 1970-01-01
    • 2017-05-11
    • 2013-05-09
    • 2011-11-10
    • 1970-01-01
    • 2013-04-22
    相关资源
    最近更新 更多