Search code examples
c#.net-corepostsharpasp.net-apicontroller

How do I use OnExceptionAspect to return ActionResult<IEnumerable<Model>>


I have a simple ApiController that I am trying to catch and return an error. This was for a quick OnExceptionAspect demo but I ran into a snag: I can't figure out how to return BadRequest as the args.ReturnValue. I thought it would be simpler than this. This is my first time using PostSharp in a very long time and certainly the first time while using ASP.Net Core.

Note: I have a bad connection string on the context to force a quick error (not shown).

ParentController

[HttpGet("Get/{studentId}")]
[ActionResultExceptionAspect(StatusCode = HttpStatusCode.BadRequest)]
public ActionResult<IEnumerable<ParentModel>> RetrieveParents(string studentId)
{
    var query = Context.ParentViews
        .Where(x => x.StudentID == studentId)
        .Select(s => EntityMapper.MapFromEntity(s));

    return query.ToArray();
}

ActionResultExceptionAspect

public override void OnException(MethodExecutionArgs args)
{
    args.FlowBehavior = FlowBehavior.Return;
    args.ReturnValue = ((StudentControllerBase)args.Instance).BadRequest();
}

I get an error of:

System.InvalidCastException: Unable to cast object of type 'Microsoft.AspNetCore.Mvc.BadRequestResult' to type 'Microsoft.AspNetCore.Mvc.ActionResult`1[System.Collections.Generic.IEnumerable`1[Student.Models.ParentModel]]'.

Solution

  • The problem seems to be an instance based issue. I see a lot of solutions that seem overly complicated for what I needed so I went with the simplest way to resolve this until I can find something better. I have seen this as an issue specific for ActionResult<T> return types whenever generated outside the instance. This seems simple with generics for purposes of unit tests but since this is runtime and hard to resolve an unknown return type I went with Activator.CreateInstance

    My new OnException method is:

    public override void OnException(MethodExecutionArgs args)
    {
        var methType = ((MethodInfo)args.Method).ReturnType;
    
        args.ReturnValue = Activator.CreateInstance(methType, ((ControllerBase)args.Instance).BadRequest());
        args.FlowBehavior = FlowBehavior.Return;
    }
    

    I am by no means sure this is the right way to do it, but it works for this instance.