Question

I am trying to write an attribute that uses OnMethodBoundaryAspect.

public class MyValidationAttribute : OnMethodBoundaryAspect
{ 
    public override void OnEntry(MethodExecutionArgs args)
    { 
      //Set Task result after validation is performed

      if (invalid)
      {
        args.ReturnValue = Task.FromResult("blah");
        args.YieldValue= Task.FromResult("blah");
      }
    } 
}

OnEntry I am validating an entity and then updating the Yield and Return types. The signature of the method on which the aspect is applied is public async Task<Response<T>>

When I test this on a class using Task.Result, the method return what I would expect of the attribute. However if I await the method, the method does not return the data expected.

e.g.

var resultSuccess = myClass.DoIt().Result;

var resultFail = await myClass.DoIt();

Thoughts/Suggestions?

Was it helpful?

Solution

When applying your aspect to the async method you need to decide whether to apply it to the original method or to the underlying state machine generated by the compiler.

Basically, your original method is transformed by the C# compiler to initialize a new state machine struct and your original code is moved to the private void MoveNext() method of the struct.

If you want to change the return value of your method and exit immediately, then you should apply the aspect to the original method, set args.ReturnValue, and set args.FlowBehavior to FlowBehavior.Return. To apply the aspect to the original method set ApplyToStateMachine to false.

[Serializable]
public class MyValidationAttribute : OnMethodBoundaryAspect
{
    public MyValidationAttribute()
    {
        this.ApplyToStateMachine = false;
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        if (invalid)
        {
            args.ReturnValue = Task.FromResult("blah");
            args.FlowBehavior = FlowBehavior.Return;
        }
    }
}

public class MyClass
{
    [MyValidation]
    public async Task<string> DoIt()
    {
        // ...
    }
}

P.S. The property args.YieldValue is meaningful only when used with iterator methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top