PostSharp MethodExecutionTag 在方面丢失
PostSharp MethodExecutionTag lost over aspect
我写了2个截取,1个是关于参数验证传递,另一个是错误处理。
拦截 #1 抛出错误(如预期的那样),自定义对象附加到 MethodExecutionArgs.MethodExecutionTag
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
...
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
args.MethodExecutionTag = state;
throw new ArgumentException(errMsgs.ToString());
但是,这个 MethodExecutionTag 在错误处理中丢失了。
public class ExceptionHandlingWithResponseAttribute : ExceptionHandlingAttribute
{
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ExecutionState state = args.MethodExecutionTag as ExecutionState;
if (state != null)
{
// as debugging, expected to be here, but it's not
}
我在 MethodExecutionArgs.GetHashCode() 上做了一个简单的检查,得到了不同的值。
我为 Web Api 应用程序设计了一个类似的应用程序,它按预期工作,但我无法调试它,因为我正在通过单元测试进行测试。
这是某种错误吗,或者我该如何解决?
这是设计使然。执行标签在方面之间是隔离的。
假设您有一个事务和一个缓存方面。两者都在 OnEntry 中设置执行标签并尝试在 OnExit 中检索它。来自事务方面的标签被缓存方面覆盖,这造成了可怕的混乱。
隔离是为了避免像这样令人讨厌的事情。
解决方案可能是将两个方面合并为一个方面:
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
...
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
args.MethodExecutionTag = state;
throw new ArgumentException(errMsgs.ToString());
}
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ExecutionState state = args.MethodExecutionTag as ExecutionState;
if (state != null)
{
// as debugging, expected to be here, but it's not
}
}
}
或者,可以直接处理验证结果而不是抛出异常。
更新(基于 Kelmen 的自定义异常想法):
public class ValidationException : Exception
{
public ExecutionState State { get; private set; }
public ValidationException(ExecutionState state)
{
State = state;
}
}
[Serializable]
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
throw new ValidationException(state);
}
}
[Serializable]
public class ExceptionHandlingWithResponseAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ValidationException validationException = args.Exception as ValidationException;
if (validationException != null)
{
// handle the exception
}
else
{
// just rethrow
args.FlowBehavior = FlowBehavior.RethrowException;
}
}
}
我写了2个截取,1个是关于参数验证传递,另一个是错误处理。
拦截 #1 抛出错误(如预期的那样),自定义对象附加到 MethodExecutionArgs.MethodExecutionTag
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
...
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
args.MethodExecutionTag = state;
throw new ArgumentException(errMsgs.ToString());
但是,这个 MethodExecutionTag 在错误处理中丢失了。
public class ExceptionHandlingWithResponseAttribute : ExceptionHandlingAttribute
{
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ExecutionState state = args.MethodExecutionTag as ExecutionState;
if (state != null)
{
// as debugging, expected to be here, but it's not
}
我在 MethodExecutionArgs.GetHashCode() 上做了一个简单的检查,得到了不同的值。
我为 Web Api 应用程序设计了一个类似的应用程序,它按预期工作,但我无法调试它,因为我正在通过单元测试进行测试。
这是某种错误吗,或者我该如何解决?
这是设计使然。执行标签在方面之间是隔离的。
假设您有一个事务和一个缓存方面。两者都在 OnEntry 中设置执行标签并尝试在 OnExit 中检索它。来自事务方面的标签被缓存方面覆盖,这造成了可怕的混乱。
隔离是为了避免像这样令人讨厌的事情。
解决方案可能是将两个方面合并为一个方面:
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
...
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
args.MethodExecutionTag = state;
throw new ArgumentException(errMsgs.ToString());
}
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ExecutionState state = args.MethodExecutionTag as ExecutionState;
if (state != null)
{
// as debugging, expected to be here, but it's not
}
}
}
或者,可以直接处理验证结果而不是抛出异常。
更新(基于 Kelmen 的自定义异常想法):
public class ValidationException : Exception
{
public ExecutionState State { get; private set; }
public ValidationException(ExecutionState state)
{
State = state;
}
}
[Serializable]
public class ValidateArguementAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
var state = new ExecutionState
{
ReturnExactErrorMessage = true,
};
throw new ValidationException(state);
}
}
[Serializable]
public class ExceptionHandlingWithResponseAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
ValidationException validationException = args.Exception as ValidationException;
if (validationException != null)
{
// handle the exception
}
else
{
// just rethrow
args.FlowBehavior = FlowBehavior.RethrowException;
}
}
}