2

I have a get method like this...

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

and I want to pass in a query string like this:

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

I would like to do this without having to declare each parameter in my parameter list. e.g.

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

I want to avoid doing this because my class has several dozen parameters. I know that you can do binding with [FromQuery] Customer customer, but I don't think that's quite what I'm looking for.

Is there a way to do this dynamically?

1
  • 1
    What about [FromQuery] Dictionary<string, string>? Commented Feb 23, 2019 at 2:59

2 Answers 2

2

I ended up doing something like this

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

and then in a separate 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;
    }
}

There's still a lot more that needs to be done here, but I think this is an ok start.

Sign up to request clarification or add additional context in comments.

Comments

1

If you just want to access the query parameters through the HttpContext and forget about action parameters, you can just omit the parameters entirely. ASP.NET Core does not evaluate the query string as part of the action route (which also means you cannot create overloads based off query parameters unless you specify a different route via attribute routing).

4 Comments

The downvote may be warranted, but it would be nice if you at least added a comment explaining why you downvoted.
Wasn't me : P I do think that either [FromQuery] Dictionary<string,string> or the query code I have above would pretty much accomplish the same thing. I don't really know what I was hoping for here.
I didn't think it was you :) I'm glad you found some options that may work for you.
Did you try var param1 = HttpContext.Current.Request.QueryString["param1"]?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.