Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# Filtering with JSON

0.00/5 (No votes)
16 Sep 2010 1  
Part 2 of creating a dynamical filtering mechanism in C#
filter.jpg

Introduction

In the first part, I presented a small JSON object model that can be used as a way to preserve the structure of a filter (used by jqGrid). In this second part, we'll take the model and convert it to a server-side filter.

Using the Code

So here are the entities behind the design:

public class Group
{
    public GroupOperator Operator { get; set; }

    public List<Rule> Rules { get; set; }

    public List<Group> Groups { get; set; }
}
	
public class Rule
{
    public string Field { get; set; }

    public RuleOperator Operator { get; set; }

    public string Data { get; set; }
}

Using these classes, we can replicate any filter created on the client side. In terms of LINQ, the Rule is equivalent to a lambda expression and the Group class is equivalent to an expression tree. We can therefore write the methods that translate the model into System.Linq.Expressions.Expression:

From Rule to lambda expression:

public Expression ToExpression(Type parameterType, ParameterExpression param) {
    // get the property that will be evaluated
    PropertyInfo pi = null;
    MemberExpression member = null;
    
    if (this.Field.Contains(".")) // check for subproperties
    {
        ....
    }
    else {
        pi = parameterType.GetProperty(this.Field);
        member = Expression.PropertyOrField(param, this.Field);
    }
    
    ConstantExpression constant = this.Operator == RuleOperator.IsNull || 
	this.Operator == RuleOperator.NotNull
            ? Expression.Constant(null, pi.PropertyType)
            : Expression.Constant(this.CastDataAs(pi.PropertyType), pi.PropertyType);
            
    switch(this.Operator) {
        case RuleOperator.IsNull: // it's the same for null
        case RuleOperator.Equals:
             return Expression.Equal(member, constant);
        ....
    }
    
    return null;
}

From Group to expression tree:

    public Expression<func><t, bool> ToExpressionTree<t>(){
        Type t = typeof(T);
        
        // create a parameter expression that can be passed to the rules
        ParameterExpression param = Expression.Parameter(t, "p");
        
        // get the expression body. This consists of all subgroups and rules
        Expression body = GetExpressionFromSubgroup(this, t, param);
        
        if (body == null)
            return null;
        else 
            return Expression.Lambda<func<t, bool>>(
                            body,
                            new ParameterExpression[] { param }
                       );
    }
    
    protected Expression GetExpressionFromSubgroup
	(Group subgroup, Type parameterType,ParameterExpression param) {
        Expression body = null;
        .....
        return body;
    }
}

I built a small helper called WebHelper to help me with the serialization and deserialization. To put it all in one, I also added the JSONToExpressionTree method that converts the serialized JSON into an expression tree.

So let's run some tests to see if it all goes well! We will need a simple domain:

public class Country {
    public Country() { }
    
    public int Id { get; set; }
    public string Name { get; set; }
    
    public Continent Continent { get; set; }
}

public class Continent {
    public Continent() { }
    
    public string Name { get; set; }
    
    public IList<country> Countries { get; set; }
}

And a filter:

Group g = new Group() { Operator = GroupOperator.And };
g.Rules.Add(new Rule() { Field = "Continent.Name", 
	Operator = RuleOperator.StartsWith, Data = "E" });

Conclusion

Hope you enjoyed this. The next article will merge the two in an easy to use application.

Link

Part 1 of creating a dynamical filtering mechanism in C#

History

  • 16th September, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here