在 MVC Core 中动态按查询字符串过滤?

Filter by query string dynamically in MVC Core?

我有一个这样的获取方法...

[HttpGet]
public async Task<ActionResult<IEnumerable<Customer>>> GetCustomers()
{
    var queryString = HttpContext.Request.Query;
    return await _context.Customers.Take(7).ToListAsync();
}

我想传递这样的查询字符串:

https://localhost:44315/api/customer?param1=1&param2=String Value

我想执行此操作而不必在我的参数列表中声明每个参数。例如

[HttpGet]
public async Task<ActionResult<IEnumerable<Customer>>> GetCustomers(int param1, string param2)
{
    var queryString = HttpContext.Request.Query;
    return await _context.Customers.Take(7).ToListAsync();
}

我想避免这样做,因为我的 class 有几十个参数。我知道您可以使用 [FromQuery] Customer customer 进行绑定,但我认为这不是我想要的。

有没有办法动态地做到这一点?

如果您只想通过 HttpContext 访问查询参数而忘记操作参数,则可以完全省略参数。 ASP.NET Core 不会将查询字符串评估为操作路由的一部分(这也意味着您不能基于查询参数创建重载,除非您通过属性路由指定不同的路由)。

我最终做了这样的事情

   //GET: api/customer
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Customer>>> GetCustomers()
    {
        var queryParams = HttpContext.Request.Query;
        var collection = _context.Customers.FilterByQueryParams(queryParams);
        return await Task.FromResult(collection.ToList());
    }

然后在单独的 class

public static class DynamicFilterExtensionMethods
{
    public static IEnumerable<T> FilterByQueryParams<T>(this IEnumerable<T> collection, IQueryCollection queryParams) where T : new()
    {
        var classType = typeof(T);
        var propList = classType.GetProperties();
        //accountNumber ==> accountNumber, AccountNumber ==> accountNumber
        var props = new Dictionary<string, PropertyInfo>(propList.Select(x => new KeyValuePair<string, PropertyInfo>(Char.ToLowerInvariant(x.Name[0]) + x.Name.Substring(1), x)));

        foreach (var param in queryParams) {
            if (props.ContainsKey(param.Key)) {
                var prop = props[param.Key];
                   if (prop.PropertyType.IsPrimitive) {
                    if (param.Value.Count == 1)
                    {
                        collection = collection.Where(x => prop.GetValue(x, null).ToString() == param.Value.First());
                    }
                    else {
                        var aggregate = new List<T>();
                        foreach (var value in param.Value) {
                            aggregate = aggregate.Union<T>(collection.Where(x => prop.GetValue(x, null).ToString() == value)).ToList();
                        }
                        collection = aggregate.AsEnumerable();
                    }
                }
            }
        }

        return collection;
    }
}

这里还有很多事情要做,但我认为这是一个好的开始。