Reputation: 14369
I want to order an IEnumerable
on a column that's provided by the user at runtime. To dynamically build a LINQ, I know that I can:
xyz.OrderBy(myExpression.Compile());
and,IEnumerable
as IQueryable
by calling xyz.AsQueryable()
and then do .OrderBy(userInputString);
.Simple question about the third approach above - Why isn't the dynamic query building ability provided on IEnumerable
s directly?
Upvotes: 0
Views: 108
Reputation: 21487
There is very little benefit in doing so, while there are many drawbacks. In any case, you need to (or a library does) be able to convert a string into a set of instructions on what to do, and you need to be able to parse the string to make sure they aren't asking for something you don't want it to do. Most programmers (especially new ones) don't understand the security ramifications of what they do, so they land up unknowingly writing insecure code. Not having such a library forces the programmer to actually parse the input which they should have always been doing anyhow.
A typical discussion would likely go: Why can't we at least order passing in the name of a property of an object? Ok. Then why can't we select by passing in a name of a property? Ok. Then why can't we filter by passing in a string expression like prop=="this"? And then of all a sudden we have security issues all over the place because programmers don't bother to check the user didn't supply something like this" or "1"="1 as their input.
So programmers start writing code like:
var usercheckstring="Username='"+txtUser.Text+"' and Password='"+txtPassword.Text+"'";
var user=db.Users.Where(usercheckstring).FirstOrDefault();
if (user!=null)
{
... Log in the user here ...
}
and then cry when some hacker types in ' or Admin='1
as a password, and it logs them in as the admin. Then people say C# or LINQ is insecure when it was always the programmer's fault.
And while Scott Gu is a good guy, and almost indisputably a great programmer, even he falls into the same pitfall, and gives out some incredibly bad advice on his DynamicLinq blog entry here: http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library where he says you can do this:
.Where(String.Format("CategoryID={0}" & Request.QueryString["id"])
WHOA! Sure, you CAN do that, but you sure as heck SHOULD NEVER (besides the fact it has a syntax error). Bad Scott, BAD! He just showed the world how to do a DynamicLinq injection. While not quite as bad as your typical SQL Injection attack, it suffers in the same way.
It is ALWAYS a bad idea to blindly use user supplied data, which is what 99% of what people want to do with Dynamic LINQ (I either found that statistic on the internet, or I just made it up). They can't figure out how to do it with normal LINQ, want to take a bad shortcut, and then get burnt. A switch/case isn't that hard, takes a few lines of code, isn't insecure, and will run much faster than doing reflection over an object to try and convert a string to a lambda.
Upvotes: 1
Reputation: 14369
I had imported a Dynamic Query class to my project from the Dynamic Query Library available on ScottGu's blog. This provided me with extension methods to build dynamic queries by providing only the field name for ordering the collection, at runtime. Using this library I could things like the following:
var employees = new List<Employee>
{
new Employee
{
DeptId = 1,
Id = 1,
Name = "JKL"
},
new Employee
{
DeptId = 1,
Id = 2,
Name = "ABC"
},
new Employee
{
DeptId = 5,
Id = 3,
Name = "LMN"
}
};
var query1 = employees.OrderBy(e => e.Name);
foreach (var employee in query)
{
Console.WriteLine(employee.Name); //Prints names
}
var query2 = employees
.AsQueryable()
.OrderBy("Name");
foreach (var employee in query2)
{
Console.WriteLine(employee.Name); //Prints exact output as foreach loop above.
}
Note that while in query1
I have to write a lambda in the .OrderBy()
, I am only providing the field name directly in query2
but I need to do a .AsQueryable()
on the collection.
The Employee is defined as:
public class Employee
{
public int Id;
public string Name;
public int DeptId;
}
So, the answer to the question is that if I want to know why can't I do a OrderBy("Name")
directly on a IEnumerable
, I should either drop a mail and ask ScottGu or read the source code for hints about the same.
Upvotes: 0