PostSharp MethodExecutionTag丢失了方面

时间:2015-11-02 09:32:32

标签: postsharp

我写了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()进行简单的检查,得到不同的值。

我有类似的设计用于网络Api应用程序,它按预期工作,但我无法调试它,因为我正在测试单元测试。

这是一些bug,或者我该如何解决?

1 个答案:

答案 0 :(得分:0)

这是设计的。执行标签在各个方面之间是隔离的。

想象一下,您有一个事务和一个缓存方面。两者都在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;
        }
    }
}