简体   繁体   English

如何:处理异常,最佳实践

[英]how to: handle exceptions, best practices

need to implement a global error handling, so maybe you can help out with the following example... 需要实现全局错误处理,所以也许您可以帮助以下示例...

i have this code: 我有这个代码:

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;
            }
        }

and the md5 as well: 和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();
        }

so, how would i go about handling exceptions from these functions? 那么,我将如何处理这些函数的异常? they first one is called from the Default.aspx page. 它们首先从Default.aspx页面调用。 the second one is only called from other functions from the class library. 第二个只从类库中的其他函数调用。

what is the best practice? 什么是最佳做法?

  • surround code INSIDE each function with try-catch 环绕代码INSIDE每个函数都有try-catch
  • surround the FUNCTION CALL with try-catch try-catch包围FUNCTION CALL
  • something else?? 别的什么?

what to do if exceptions happen? 异常发生时该怎么办?

in this example: this is a user sign in, so somehow even if everything fails, the user should get some meaningful info - along the lines: sign in ok (just redirect), sign in not ok (wrong user name / password), sign in not possible due to internal problems, sorry (exception happened). 在这个例子中:这是一个用户登录,所以即使一切都失败,用户也应该获得一些有意义的信息 - 沿着这样的行:登录ok(只是重定向),登录不正常(用户名/密码错误),由于内部问题而无法登录,抱歉(发生异常)。

for the first function i am worried if there is a problem with database access. 对于第一个函数我担心如果数据库访问有问题。 not sure if there is anything that needs to be handled in the second one. 不确定是否有任何需要在第二个处理。

thnx for the info. thnx的信息。 how would you do it? 你会怎么做? need specific info on this (easier for me to understand), but also general info on how to handle other tasks/functions. 需要具体的信息(我更容易理解),还有关于如何处理其他任务/功能的一般信息。

i looked around the internet but everyone has different things to say, so unsure what to do... will go with either most votes here, or most logicaly explained answer :) thank you. 我环顾了互联网,但是每个人都有不同的想法,所以不确定该做什么...会选择大多数选票,或大多数逻辑解释答案:)谢谢。

Two golden rules: 两条黄金法则:

  1. Throw an exception if a method can't do what its name says it does. 如果某个方法无法按照其名称所做的操作,则抛出异常。
  2. Don't catch exceptions unless you know exactly what to do with them. 除非您确切知道如何处理异常,否则不要捕获异常。

Remember that an exception indicates that something has gone wrong, and that particular something may not be what you think. 请记住,异常表示出现了问题,而且某些特定内容可能不是您的想法。 (Out of memory, stack overflow, 3rd party service gone down, botched deployment resulting in missing assemblies, mis-configuration, security exceptions etc). (内存不足,堆栈溢出,第三方服务中断,部署拙劣导致程序集丢失,配置错误,安全异常等)。

With very few exceptions, the only place you should see Pokemon exception handling is at the topmost level of your code, where the exception should be published somewhere. 除了极少数例外,您应该看到Pokemon异常处理的唯一位置是代码的最顶层,其中异常应该在某处发布。 For example, in the Application_Error method in your global.asax file. 例如,在global.asax文件中的Application_Error方法中。

Here are some links for you that you may find helpful: 以下是一些您可能会觉得有用的链接:

Your library code or the code that is used by higher-layers in your application must always only throw exceptions and never worry about how to deal with them. 您的库代码或应用程序中更高层使用的代码必须始终只抛出异常,而不必担心如何处理它们。

This is important because you may use this library at many places for different purposes. 这很重要,因为您可以在许多地方使用此库以用于不同目的。

In your application presentation layer, if you're consuming a library code and you're aware about the possible exceptions then do catch them with try/catch. 在您的应用程序表示层中,如果您正在使用库代码并且您知道可能的异常,那么请使用try / catch捕获它们。

Since you're using asp.net I'd recommend to write a common page-base class and work some error handling mechanism in Page_Error event that catches all un-handled exceptions on the page. 由于您使用的是asp.net,我建议您编写一个通用的基于页面的类,并在Page_Error事件中使用一些错误处理机制来捕获页面上所有未处理的异常。

Even beyond that you can use Application_Error even in global.asax to catch any un-handled exception in any part of the application, Modules, Handler, services, pages etc. 除此之外,即使在global.asax中也可以使用Application_Error来捕获应用程序的任何部分,模块,处理程序,服务,页面等中的任何未处理的异常。

I'd strongly recommend to not make it a general practice to handle all exception in global Application_Error. 我强烈建议不要在全局Application_Error中处理所有异常。

You need to think about the contracts that the methods define. 您需要考虑方法定义的合同。 If a method can't fulfill its contract then you need an exception. 如果某个方法无法履行其合同,那么您需要一个例外。 Exceptions thrown within the method should be translated into exceptions that make sense from the point of view of the contract of the method. 方法中抛出的异常应该转换为从方法契约的角度来看有意义的异常。

In the first case, I would catch any exceptions that can be thrown by statement execution (eg database errors) and translate them into something like an AuthorisationException. 在第一种情况下,我会捕获任何可以由语句执行引发的异常(例如数据库错误)并将它们转换为类似AuthorizationException的内容。 Allowing the exception to propagate straight up doesn't make sense from the point of view of the methods contract. 从方法契约的角度来看,允许异常直接传播是没有意义的。 For instance it doesn't make sense to allow a database exception to escape from the method when the method is fulfilling the contract of whether the author is authorised. 例如,当方法履行作者是否被授权的合同时,允许数据库异常从该方法中逃脱是没有意义的。

Using this idea of the method as a contract allows you to make the right decisions. 将这种方法的概念作为契约使您可以做出正确的决定。 If a method contract is logging into the database, or some database manipulation, then it might well make sense to allow the exceptions to propagate. 如果方法契约登录到数据库或某些数据库操作,那么允许异常传播可能是有意义的。

Getting specific: Using the first example: 具体:使用第一个例子:

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");
        }
    }

You might also like to set the inner exception on the AuthorisationException: 您可能还想在AuthorisationException上设置内部异常:

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

Then your client code can do this: 然后你的客户端代码可以这样做:

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

You may decide that you don't want to catch the AuthorisationException at the immediate calling site since you can't notify the user. 您可能决定不想在即时呼叫站点捕获AuthorisationException,因为您无法通知用户。 So you may let it propagate up to a level where you can do something with it. 所以你可以让它传播到你可以用它做某事的水平。

Hope that helps! 希望有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM