Turning Data Into Code With Expressions

December 31st, 2008

Expressions are language elements that allow you to build code structures on the fly, and then execute those structures.  Expression Trees are what make LINQ go, but there is nothing stopping you from putting their power to your own evil purposes.

I’m not going to go into what Expressions, Lambdas, LINQ, etc. specifically are, since that ground is well covered

For a recent project, I wrote a permissions system based client specifications that didn’t correspond to what is provided by Membership services, yet wasn’t complicated enough to bring in functionality like Rhino.Security.  One goal was to make the security as declarative as possible so that developers could specify what was required without needing to concern themselves with the guts of the system.  For example a button might require the “ManageBilling” permission to be visible, so you’d define the button as:

<uc:SomeButton … RequiresPermission=”ManageBilling” />

And, everything was good.

And then the client realized that the button should require ManageBilling OR ManageInventory AND ManageClientRecord permissions.  There are plenty of ways to make this happen but I wanted to keep things declarative, so you’d specify the button as:

<uc:SomeButton … RequiresPermission=”ManageBilling | ManageInventory & ManageClientRecord” />

So I need to turn the RequiresPermission string into code that looks like this:

bool permissionGranted = verify("ManageBilling") ||
                         verify("ManageInventory") &&
                         verify("ManageClientRecord");
if (!permissionGranted) throw new SecurityException();

With Expressions, this turns out to be straightforward.  We’ll need an ExpressionBuilder, which takes the permission string, a verify function, and returns an Expression<Func<bool>>. 

image

The permission string is parsed into PermissionExpressionTokens and OperatorExpressionTokens, following a process that is instantly familiar to anybody who’s sat through a CS interpreters class.  (Since my language consists of two rules and not much else, I thought using something like Antlr to generate the parser would have been overkill.)  This structure is returned from the parser as a wanna-be abstract syntax tree.

image

And once you’ve got the parsed statement, the rest is figuring out the Expression syntax.  Permission nodes get turned into a simple Expression<Func<bool>> representing a call to the verifier.

image

Operators require a little more work, but not much… we need to build BinaryExpressions, where the left-hand side is always going to be a Permission (see above) and the right hand side uses recursion to build either a Permission or another level for an Operator.  

image

Finally, we need to convert BinaryExpression back into something executable, so at the top of the tree:

image

To use the Expression, you’d have code something like this:

public bool VerifyPermissions(string permissions) {
   var expr = new PermissionExpressionBuilder()
      .Build(permissions, Verify);
   // where Verify is "bool Verify(string permissionName)"

   return expr.Compile().Invoke();
}

Contraindications

I didn’t bother with implementing precedence.  For the needs of this app, it wasn’t necessary.  If I needed more operators then I’d probably generate my parser using something like ANTLR.

I’m not sure what performance profile Compiling and Invoking a lot of Expressions has.  In testing, the CPU used for this was nothing compared to the eternity required to render HTML and transmit that HTML back and forth.  The compiling didn’t show up at all vs. load testing at the scale we were working at, but maybe it’d be a problem for your project.

 

So, there you go.  Create your own Expressions on the fly and turn them into running code, way easier than using Reflection.Emit.  Writing all of this took a few hours one morning, most of that time spent figuring out how to turn BinaryExpressions into LambdaExpressions that I could be invoked.

I’ve put the sample code up, including a few tests showing how the pieces fit together.

Tony Rasa Esoterica

  1. No comments yet.
Comments are closed.