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