2
votes

Comment pourrais-je obtenir un paramètre d'une action à partir de ResultExecutingContext lors de l'utilisation d'un filtre

Je crée un filtre de résultats personnalisé qui implémente l'interface IAsyncResultFilter . Dans ce filtre, j'ai besoin de la valeur réelle retournée par l'action, mais j'ai également besoin d'un paramètre de cette action (ce paramètre provient de la chaîne de requête et est utilisé pour la pagination). Le problème est que je n'ai pas trouvé de moyen d'obtenir la valeur du paramètre directement à partir du ResultExecutingContext qui est la variable dont je dispose dans l'implémentation du filtre de résultat

J'ai essayé d'obtenir le paramètre value en utilisant le context.ActionDescriptor.Parameters, mais c'est une collection de ParameterDescriptor, et je n'ai pas pu en obtenir la valeur réelle, juste une instance de ParameterDescriptor

J'ai pu obtenir le mediaType des en-têtes et aussi la chaîne de requête elle-même, mais pas la chaîne de requête liée au type PagingModel.

Est-il possible d'obtenir ce paramètre à partir de la variable ResultExecutingContext ?

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


1 commentaires

Essayez de regarder dans context.RouteData. Il doit avoir toutes les clés et valeurs


3 Réponses :


1
votes

Pour obtenir PagingModel , vous pouvez essayer TryUpdateModelAsync comme

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


1 commentaires

Salut Tao, merci beaucoup. Cela a fonctionné, je devais juste apporter un petit changement à votre réponse. J'ai dû lancer le contrôleur sur ControllerBase au lieu de simplement Controller. Je n'ai pas pu trouver la classe Controller dans Microsoft.AspNetCore.Mvc



0
votes

Sur la base de la réponse de Tao, j'ai créé une belle méthode statique qui vous permet d'obtenir n'importe quel paramètre de n'importe quel type d'un contrôleur:

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


0 commentaires

1
votes

Dans .net core 3.1, vous pouvez récupérer les paramètres et leurs valeurs dans votre filtre comme ceci:

foreach (var argument in context.ActionArguments)
{
    object parameterValue = argument.Value;
    string parameterName = argument.Key;
}

Ce code récupère les valeurs des paramètres pour les types de données de base. Vous pouvez étendre ce code pour gérer des objets et des listes de valeurs. La propriété argument.Value contiendra les valeurs des propriétés des objets ou la liste de valeurs.


0 commentaires