Using CSharpCodeProvider to Create Custom Functions

I have an existing asp.net application (C #). I need to provide a way for users to create flexible computing rules to calculate effective date based on hiring and registration.

Some examples of rules that can be used:

  • Later from the number of hired or registered users
  • HireDate + 90 days
  • First month after registration date
  • If the registration date is before the 15th day of the month, then the effective date is the 1st day of the next month. If it is on or after 15, it is the 1st month after that.

I started with a few offset fields (date offset, month offset, etc.), but when I come across new requirements, I start to realize that the current approach isn't flexible enough.

I would like to do this so that the end user can define a function that returns a date with two parameters (hiredate, enrollmentdate) and stores that function in the database. When I need to compute effectivedate, I would pull this function out of the database by executing it, passing parameters to get my efficiency.

My main reaction was to find a DSL that would allow me to define date manipulation functions and integrate them into my solution. However, my search for a suitable DSL showed nothing.

Now I'm wondering if CSharpCodeProvider can work as a component for a solution. If I pulled a string from the database and compiled it using CsharpCodeProvider, can I ensure that the resulting code matches the function signature (takes 2 datetime parameters and returns a date)?

Is there a way to ensure that the function has no side effects? For example, No I / O. No read or session, cache or application.

+1


source to share


2 answers


See my recent answer here: Parsing "DateTime.Now"?

As such, you can easily use an existing library like FLEE to parse expressions and emit IL for those rules. If you look at the examples, you can see how to set up variables for custom expressions in order to use them. For example, you can define a "rule" that consists of some input variables (for example, HireDate

or EnrollmentDate

) and a custom expression / predicate that returns a date. If you expose members DateTime

like me in the linked answer, then users can use them as well.

As a quick example, not tested but should give you an idea.

You can tweak some custom functions to help, like getting the first day of the month:

public static class CustomFunctions
{
    public static DateTime GetFirstDayOfMonth(DateTime date)
    {
        return new DateTime(date.Year, date.Month, 1);
    }
}

      



Basic FLEE setup (you will need to tweak / tweak as needed)

ExpressionContext context = new ExpressionContext();

//Tell FLEE to expect a DateTime result; if the expression evaluates otherwise, 
//throws an ExpressionCompileException when compiling the expression
context.Options.ResultType = typeof(DateTime);

//Instruct FLEE to expose the `DateTime` static members and have 
//them accessible via "DateTime".
//This mimics the same exact C# syntax to access `DateTime.Now`
context.Imports.AddType(typeof(DateTime), "DateTime");
context.Imports.AddType(typeof(CustomFunctions));

//Expose your key variables like HireDate and EnrollmentDate
context.Variables["HireDate"] = GetHireDate(); //DateTime I suppose
context.Variables["EnrollmentDate"] = GetEnrollmentDate(); //DateTime I suppose

//Parse the expression, naturally the string would come from your data source
IGenericExpression<DateTime> expression = context.CompileGeneric<DateTime>(GetYourRule(), context);

DateTime date = expression.Evaluate();

      

Then your rules might look like this:

string rule1 = "if(HireDate > EnrollmentDate, HireDate, EnrollmentDate)";
string rule2 = "HireDate.AddDays(90)";
string rule3 = "GetFirstDayOfMonth(EnrollmentDate.AddMonths(1))";
string rule4 = "GetFirstDayOfMonth(EnrollmentDate.AddMonths(if(EnrollmentDate.Day < 15, 1, 2)))"; 

      

+2


source


The following link has what you need. Basically it's a pluggable DSL that allows an endless schedule of dates and sets to define and then pass functions, intersect, merge, etc.



http://code.google.com/p/drules/

0


source







All Articles