65.9K
CodeProject 正在变化。 阅读更多。
Home

使用自定义属性和堆栈跟踪进行异常处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (9投票s)

2013年11月23日

CPOL

2分钟阅读

viewsIcon

48956

downloadIcon

397

使用自定义属性和堆栈跟踪进行异常处理。

引言

异常处理是每个应用程序中非常重要的一部分。它应该向最终用户提供适当的消息,以便他们能够正确地向支持团队解释问题。这将有助于快速识别和解决问题。 

背景

我正在填写一份申请表,然后提交了它。但它提示了一条通用的消息,即“存在技术问题,您无法继续,请联系管理员”。我不知道确切的问题是什么。如果应用程序提示了实际消息,我本可以理解。因此,我开发了一个小型实用工具,它使用堆栈跟踪和自定义属性生成实际的失败消息。在这里,我们不需要为所有方法实现 try catch 块。

为了实现这种方法,我们需要将自定义属性放置在所有方法之上,并且它应该描述该方法实际执行的操作,以便在发生异常时为每个步骤生成消息。

我们可以在哪里使用

由于此实用工具从整个堆栈跟踪中提取方法描述,它将向最终用户披露业务流程。这不需要,并且可能成为黑客的漏洞;因此,这种方法对于执行复杂算法的内部工具非常有用,如果您不想披露任何操作,我们不需要为特定方法指定描述。

已知问题

在发布版本中,我们不能拥有所有步骤。如果您确实需要所有步骤,我们可以通过更改构建配置设置来获取它们。

  • 项目-> 属性 -> 构建
  • 配置 = 发布版
  • 优化代码 = 否(未选中)
  • 高级构建设置:调试信息:完整

源代码

主应用程序如下

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var loanValidator = new LoanValidator();
            loanValidator.CheckLoanApplication();
        }
        catch (Exception ex)
        {
            string exceptionMessage=ExceptionHelper.GetDetailMessage(ex);
            Console.Write(exceptionMessage);
            Console.Read();                
        }
    }
}

输出如下所示

Sample Image

自定义 Attribute 源代码如下

public class MethodDescription : Attribute
{
    public MethodDescription(string description)
    {
        this.Description = description;
    }
    public string Description { get; set; }
}

贷款验证器源代码如下

public class LoanValidator
{
    [MethodDescription("Validating loan application")]
    public bool CheckLoanApplication()
    {
        bool isValidPersonalDetail = CheckPersonalDetail();
        bool isValidEmploymentDetail = CheckEmploymentDetail();
        bool isValidBankAccountDetail = CheckBankAccountDetail();

        if (isValidPersonalDetail && 
        isValidEmploymentDetail && isValidBankAccountDetail)
            return true;
        else
            return false;
    }

    [MethodDescription("Checking personal detail")]
    private bool CheckPersonalDetail()
    {
        return true;
    }

    [MethodDescription("Checking employment detail")]
    private bool CheckEmploymentDetail()
    {
        return true;
    }
    [MethodDescription("Checking bank account detail")]
    private bool CheckBankAccountDetail()
    {
        CheckAnyOutstanding();
        return true;
    }

    [MethodDescription("Checking outstanding detail from common web server")]
    private bool CheckAnyOutstanding()
    {
        throw new WebException();
        return true;
    }
}

异常处理助手源代码如下所示

public class ExceptionHelper
{
    /// <summary>
    /// Frame the detail message from exception
    /// </summary>
    /// <param name="ex"></param>
    /// <returns></returns>
    public static string GetDetailMessage(Exception ex)
    {
        StringBuilder messageBuilder = new StringBuilder();
        Type attributeType = typeof(MethodDescription);            
        
        int step = 1;

        var attributes = GetStackTraceSteps<MethodDescription>(ex);
        if(attributes!=null && attributes.Count>0)
        messageBuilder.AppendLine(string.Format
        ("Sorry there is a problem while processing step {0}:",attributes.Count));
        foreach (var attribute in attributes)
        {
            messageBuilder.Append(string.Format
            ("Step {0}: {1}", step.ToString(), attribute.Description));
            messageBuilder.AppendLine();
            step++;
        }
        messageBuilder.AppendLine();

        string formatedMessage = string.Format("{0}Error Description : {1}",
                                                messageBuilder.ToString(),
                                                ex.Message
                                                );

        return formatedMessage;
    }

    /// <summary>
    /// Extrace the custom attribute details from the stacktrace
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="ex"></param>
    /// <returns></returns>
    public static List<T> GetStackTraceSteps<T>(Exception ex)
    {
        List<T> traceSteps = new List<T>();
        Type attributeType = typeof(T);
        StackTrace st = new StackTrace(ex);
        if (st != null && st.FrameCount > 0)
        {

            for (int index = st.FrameCount - 1; index >= 0; index--)
            {
                var attribute = st.GetFrame(index).
                GetMethod().GetCustomAttributes(attributeType, false).FirstOrDefault();
                if (attribute != null)
                {
                    traceSteps.Add((T)attribute);

                }
            }
        }

        return traceSteps;
    }
}
© . All rights reserved.