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






4.76/5 (9投票s)
使用自定义属性和堆栈跟踪进行异常处理。
引言
异常处理是每个应用程序中非常重要的一部分。它应该向最终用户提供适当的消息,以便他们能够正确地向支持团队解释问题。这将有助于快速识别和解决问题。
背景
我正在填写一份申请表,然后提交了它。但它提示了一条通用的消息,即“存在技术问题,您无法继续,请联系管理员”。我不知道确切的问题是什么。如果应用程序提示了实际消息,我本可以理解。因此,我开发了一个小型实用工具,它使用堆栈跟踪和自定义属性生成实际的失败消息。在这里,我们不需要为所有方法实现 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();
}
}
}
输出如下所示
自定义 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;
}
}