Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could I get a parameter of an action from the ResultExecutingContext when using a Filter

I'm creating a custom result filter that implements IAsyncResultFilter interface. In this filter I need the actual value returned by the Action, but I also need a parameter from that action (This parameter comes from the query string and is used for pagination). The thing is that I haven't found a way to get the parameter value directly from the ResultExecutingContext that is the variable I have available in the result filter implementation

I've tried to get the parameter value using the context.ActionDescriptor.Parameters, but it's a collection of ParameterDescriptor, and I haven't been able to get the actual value from it, just an instance of ParameterDescriptor

I've been able to get the mediaType from the headers and also the query string itself, but not the query string binded to the PagingModel type.

Is there any way to get this parameter from the ResultExecutingContext variable?


// Action from the ApiController
[HttpGet]
[AddPaginationHeader]
public async Task<IActionResult> Get([FromQuery]PagingModel pagingModel, 
    [FromHeader(Name = "Accept")]string mediaType) {
    var pagedCollection = repository.GetPage(pagingModel);
    var shapedCollection = ShapeCollectionOfData(pagedCollection);
    return Ok(shapedCollection);
}

// AddPaginationHeader Implementation (Result Filter)
public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) {
    var result = context.Result as ObjectResult;
    if (result?.Value != null && result?.StatusCode >= 200 &&
        result?.StatusCode < 300) {
        // Trying to get the pagingModel (but getting a ParameterDescriptor type)
        var pagingModel = context.ActionDescriptor.Parameters.Where(t=>t.Name.Equals("pagingModel")).FirstOrDefault();       
        //Getting the media type
        string mediaType = context.HttpContext.Request.Headers["Accept"]
        // Getting the query string itself
        string queryString = context.HttpContext.Request.QueryString.ToString();
        //Implementation of the actual logic that needs the paging model
        // ...
        next();
    }
    return Task.CompletedTask;
}

like image 571
carlos chourio Avatar asked Sep 19 '25 16:09

carlos chourio


2 Answers

Based on the answer of Tao I created a nice static method that allows you to get any parameter of any type from a Controller:

private static async Task<TParameter> GetParameterFromAction<TParameter>(ResultExecutingContext context, string parameterName) {
    var parameterDescriptor = context.ActionDescriptor.Parameters.Where(t => t.Name.Equals(parameterName)).FirstOrDefault();
    ControllerBase controller = context.Controller as ControllerBase;
    TParameter parameter = (TParameter)Activator.CreateInstance(parameterDescriptor.ParameterType);
    await controller.TryUpdateModelAsync(parameter, parameterDescriptor.ParameterType, string.Empty);
    return parameter;
}

like image 120
carlos chourio Avatar answered Sep 21 '25 06:09

carlos chourio


For getting PagingModel, you could try TryUpdateModelAsync like

public class AddPaginationHeader : Attribute, IAsyncResultFilter
{
    // AddPaginationHeader Implementation (Result Filter)
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        //PagingModel model = new PagingModel();
        //await controller.TryUpdateModelAsync(model);
        var result = context.Result as ObjectResult;
        if (result?.Value != null && result?.StatusCode >= 200 &&
            result?.StatusCode < 300)
        {
            // Trying to get the pagingModel (but getting a ParameterDescriptor type)
            var controller = context.Controller as Controller;
            var parameterDescriptor = context.ActionDescriptor.Parameters.Where(t => t.Name.Equals("pagingModel")).FirstOrDefault();
            var parameter = Activator.CreateInstance(parameterDescriptor.ParameterType);
            await controller.TryUpdateModelAsync(parameter, parameterDescriptor.ParameterType, "");
            var pagingModel = parameter;
            //Getting the media type
            string mediaType = context.HttpContext.Request.Headers["Accept"];
            // Getting the query string itself
            string queryString = context.HttpContext.Request.QueryString.ToString();
            //Implementation of the actual logic that needs the paging model
            // ...
            next();
        }
        //return Task.CompletedTask;
    }
}
like image 42
Edward Avatar answered Sep 21 '25 07:09

Edward