Posts

Entity validation engine using c# expression rules

Validating entity data is the common task when building business applications. Very often happens that we want to separate the rules from the app code to be able to quickly change it without affecting the application. In this article we will build simple validation engine that will be evaluating rules stored as linq expressions.

In our example we will hardcode the rules in separate .cs files (based on entity type). You may also want to store the linq expressions as a string in database and also compile the code dynamically from the string and then execute the rules based on the output dll file.

validation-engine

In our case we will hard code the rule in .css files. The following example shows the rule definitions for Client entity.

  public class ClientValidationRules : BaseValidationRuleSet<Client>
   {
        public ClientValidationRules(Client arg)
        {
            RuleList.Add(new ValidationRule<Client>(
                //set the rule
                a => a.Name.Trim().Any() && !a.Name.Any(b => char.IsLower(b))
                ////
                , arg)
                {
                    //set the result
                    Message = "Name cannot be all in uppercase!",
                    ResultTypeIfFailed = ValidationResultType.ERROR,
                    SuggestionString = arg.Name.ToLower()
                });

            RuleList.Add(new ValidationRule<Client>(
                //set the rule
               a => a.DateOfBirth.AddYears(18) > DateTime.Now
                ////
               , arg)
            {
                //set the result
                Message = "You must be at lest 18 years old to register!",
                ResultTypeIfFailed = ValidationResultType.ERROR,
                SuggestionString = string.Format("Wait {0} days", DateTime.Now.Subtract(arg.DateOfBirth).TotalDays.ToString("0"))
            });
        }
    }
}

You can see that this way allows us to easily define rule’s logic based on the entity data. We can also define suggestion message for each rule separately. By setting ValidationResultType as a rule result we can for example allow to save data if this is only a warning or prevent saving the data by the user if this is an error.

The implementation is as follows. Let’s start with generic ValidationRule class containing the rule data and delegate to run.

 namespace RuleEngine
 {
    public class ValidationRule<T> where T : class
    {
        public string Message { get; set; }
        public string SuggestionString { get; set; }
        
        public ValidationResultType ResultTypeIfFailed { get; set; }

        internal Func<T, bool> RuleDelegate { get; set; }
        internal T ObjectTovalidate { get; set; }

        public ValidationRule(Func<T, bool> rule, T arg)
        {
            RuleDelegate = rule;
            ObjectTovalidate = arg;
        }

        public bool RunRuleDelegate()
        {
            return RuleDelegate(ObjectTovalidate);
        }
    }
 }

It’s base class will have the “Run” method implementation.

 namespace RuleEngine
 {
    public abstract class BaseValidationRuleSet<T> where T : class
    {
        public List<ValidationRule<T>> RuleList { get; internal set; }

        /// <summary>
        /// Initiates rule list
        /// </summary>
        public BaseValidationRuleSet()
        {
            RuleList = new List<ValidationRule<T>>();
        }

        /// <summary>
        /// Run all added rules
        /// </summary>
        /// <returns></returns>
        public ValidationResult Run()
        {
            foreach (var rule in this.RuleList)
            {
                var result = rule.RunRuleDelegate();

                if (result)
                {
                    return new ValidationResult() { IsValid = false, ResultType = rule.ResultTypeIfFailed, Message = rule.Message, SuggestionString = rule.SuggestionString };
                }
            }

            return new ValidationResult() { IsValid = true, ResultType = ValidationResultType.OK };
        }
    }
}

Let’s define ValidationResult class that will be returned after running the rule delegate.

 namespace RuleEngine
 {
    public class ValidationResult
    {
        public bool IsValid { get; set; }
        public string SuggestionString { get; set; }
        public string Message { get; set; }
        public ValidationResultType ResultType { get; set; }
    }
}

The ValidationEngine class will have the entry point for different entity validation methods. You may also want to create generic function to pass the validating object to. You also can preload all rules at runtime and evaluate dynamically using AppDomain.CurrentDomain.GetAssemblies() method.

  public class ValidationEngine: ValidationEngineBase
  {
      public ValidationResult RunProjectRules(Project project)
      {
          return new ProjectValidationRules(project).Run();
      }
      public ValidationResult RunClientRules(Client client)
      {
          return new ClientValidationRules(client).Run();
      }
   }

In order to test our solution we can use console app. We also need to load some fake data into our entities.

     static void Main(string[] args)
        {
            var validationEngine = new ValidationEngine();

            #region load entities
            var client = new Client()
                  {
                      Name = "CLIENT NUMBER1a",
                      DateOfBirth = DateTime.Now.AddYears(-10)
                  };

            var project = new Project()
            {
                Name = "PROJECT NUMBER1",
                StartDate = DateTime.Now.AddDays(1),
                EndDate = DateTime.Now.AddDays(1)
            }; 
            #endregion


            #region validate client
            Console.WriteLine("Starting client validation");

            var result = validationEngine.RunClientRules(client);

            if (!result.IsValid)
            {
                Console.WriteLine(result.Message);
                Console.WriteLine(string.Format("Suggestion: {0}", result.SuggestionString));
            }
            else
            {
                Console.WriteLine("OK");
            }
            #endregion

            Console.WriteLine("--------------------");

            #region validate project
            Console.WriteLine("Starting project validation");

            result = validationEngine.RunProjectRules(project);

            if (!result.IsValid)
            {
                Console.WriteLine(result.Message);
                Console.WriteLine(string.Format("Suggestion: {0}", result.SuggestionString));
            }
            else
            {
                Console.WriteLine("OK");
            }
            #endregion

            Console.ReadLine();
        }

I have included project files bellow for your tests.


#Article update#

We can also create simple business rule engine in very similar way, here is the implementation:

 namespace RuleEngine
 {
    /// <summary>
    /// To be extended if needed
    /// </summary>
    public abstract class BusinessRuleEngineBase
    {
        
    }

    /// <summary>
    /// Runs set of rules for different entities
    /// </summary>
    public class BusinessRuleEngine : BusinessRuleEngineBase
    {
        /// <summary>
        /// Run rules for ScheduledFlight 
        /// </summary>
        /// <param name="scheduledFlight"></param>
        /// <returns></returns>
        public bool RunBusinessRulesFor(ScheduledFlight scheduledFlight)
        {
            return new FlightBusinessRules(scheduledFlight).Run();
        }
    }
 }

Business rule implementation containing evaluating and executing delegate

/// <summary>
/// Runs delegate on the specified business rule set
/// </summary>
/// <typeparam name="T"></typeparam>
public class BusinessRule<T> where T : class
{
    public string RuleName { get; set; }
    internal Func<T, bool> RuleDelegate { get; set; }
    internal Func<T, bool> ExecuteRuleDelegate { get; set; }
    internal T ObjectToValidate { get; set; }
    internal T ObjectToApply { get; set; }

    public BusinessRule(Func<T, bool> rule, Func<T, bool> ruleApply, T arg)
    {
        RuleDelegate = rule;
        ExecuteRuleDelegate = ruleApply;
        ObjectToValidate = arg;
        ObjectToApply = arg;
    }

    /// <summary>
    /// Determines if business rule should be applied
    /// </summary>
    /// <returns></returns>
    public bool ApplyRuleDelegate()
    {
        return RuleDelegate(ObjectToValidate);
    }

    /// <summary>
    /// Applies business rule on the current entity
    /// </summary>
    /// <returns></returns>
    public bool ApplyBusinessDelegate()
    {
        return ExecuteRuleDelegate(ObjectToApply);
    }
    
}

BaseBusinessRuleSet base class

/// <summary>
/// Base class for business rule sets
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseBusinessRuleSet<T> where T : class
{
    public List<BusinessRule<T>> RuleList { get; internal set; }

    /// <summary>
    /// Initiates business rule list
    /// </summary>
    public BaseBusinessRuleSet()
    {
        RuleList = new List<BusinessRule<T>>();
    }

    /// <summary>
    /// Run all added business rules
    /// </summary>
    /// <returns></returns>
    public bool Run()
    {
        foreach (var rule in this.RuleList)
        {
            var result = rule.ApplyRuleDelegate();

            //if rule is true, run business logic
            if (result)
            {
                rule.ApplyBusinessDelegate();

                return true;
            }
        }

        return false;
    }
}

And finally the business rule set-up class.

public class FlightBusinessRules : BaseBusinessRuleSet<ScheduledFlight>
{
    /// <summary>
    /// Setup business rules for ScheduledFlight
    /// </summary>
    /// <param name="arg"></param>
    public FlightBusinessRules(ScheduledFlight arg)
    {

        RuleList.Add(new BusinessRule<ScheduledFlight>(
            //set the rule
                a => (double)arg.Passengers.Count(p => p.Type == PassengerType.AirlineEmployee) / arg.Passengers.Count > arg.FlightRoute.MinimumTakeOffPercentage
            ,
            //execute rule
                 e =>
                 {
                     //lower the base price till 100
                     if (arg.FlightRoute.BasePrice >= 100)
                     {
                         arg.FlightRoute.BasePrice -= 10;
                     }

                     //add more logic here...

                     return true;
                 },
                arg) { RuleName = "ApplyDiscountFor_AirlineEmployee" });


        RuleList.Add(new BusinessRule<ScheduledFlight>(
            //set the rule
              a => a.FlightRoute.BasePrice == 0
              ,
            //execute rule
               e =>
               {
                   //enforce minimal base price
                   arg.FlightRoute.BasePrice = 100;

                   return true;
               },
              arg) { RuleName = "EnsureMinimalBasePrice" });

    }
}

RuleEngine

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...

LINQ basic string and digit operations

Hi, today I want to show you how we can do the basic string and digit operations with the LINQ. If you are not using Linq in your current projects, you may find it very tempting to start with it. Once you learn it you will probably be using it all the time 🙂

Lets start with the function that sums the numbers that contains a given digit. We can do it in just one line of code 🙂

 public static int SumNumbers(int[] numbers, int digit)
 {
     return numbers.Where(i => i.ToString().Contains(digit.ToString())).Sum();
 }

If you want to sum number of words that contain minimum number of letters, this will be useful.

 public static int CountWords(string text, int minNumberOfLetters)
 {
     return text.Split(' ').Count(i => i.Length >= minNumberOfLetters);
 }

If you ever wanted to find the longest word in a text, here is example.

 public static string FindLongestWord(string text)
 {
     return text.Split(' ').OrderByDescending(i => i.Length).ThenBy(i => i).First();
 }

And if you want to count number of distinct words longer than given number, check this

 public static int CountWordsLongerThan(string text, int minimumLetters)
 {
     return text.Split(' ').Where(i => i.Length >= minimumLetters).Distinct().Count();
 }

This function gets list of non unique words in the string (separated by the space) and longer than 5 letters

 public static IEnumerable<string> FindNonUniqueWords(string inputText)
 {
     return inputText.ToLower().Split(' ')
       .OrderBy(i => i).GroupBy(i => i).Where(i => i.Count() > 1)
       .Select(i => i.Key).Where(i => i.Length > 5);
 }

And finally something more sophisticated, similarity calculation between two texts (for words having more than 4 letters)

 public static int CalculateSimilarity(string text1, string text2)
 {
    var words1 = text1.Split(' ').Where(i => i.Length > 4).Distinct();
    var words2 = text2.Split(' ').Where(i => i.Length > 4).Distinct();

     return words1.Intersect(words2).Count();
  }

Don’t forget to use “using System.Linq;” namespace in your project before using this. And of course parameters validation must be added to every function to be fully functional.

That’s it for now.

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...

File helpers using LINQ

When dealing with files, it is useful to have standard set of helpers to be used that we can relay on. This is when LINQ comes in handy. In this article I will present you with some useful functions that you can use in your daily programming.

Simple operation should be simple. Hence, when getting the number of lines in the text file, one line of code is just enough.

 public static long GetNumberOfLines(string filePath)
 {
     return File.Exists(filePath) ? File.ReadAllLines(filePath).Count() : 0;
 }

Getting the biggest file in the folder is also very easy with LINQ

   public static string FindTheLargestFileInDirectory(string path)
    {
        return Directory.Exists(path) && Directory.GetFiles(path).Count() > 0 ? 
               Directory.EnumerateFiles(path).Select(i => new FileInfo(i))
               .OrderByDescending(i => i.Length).FirstOrDefault().FullName : null;
    }

Similar when getting all files with the size of less than 1 Kb

   public static IEnumerable<string> FindFilesLessThanOneKiloBytesInThisFolder(string path)
    {
        return Directory.Exists(path) && Directory.GetFiles(path).Count() > 0 ?  
             Directory.EnumerateFiles(path).Select(i => new FileInfo(i))
             .Where(i => i.Length < 1024).Select(i => i.FullName) : null;
    }

You can use this function if you need to get files created in last 7 days

   public static IEnumerable<string> FindAllFilesCreatedLessThanWeekAgo(string path)
   {
        return Directory.Exists(path) && Directory.GetFiles(path).Count() > 0 ? 
               Directory.EnumerateFiles(path).Select(i => new FileInfo(i))
               .Where(i => i.CreationTime > DateTime.Now.AddDays(-7))
               .Select(i => i.FullName) : null;
   }

And finally if you want to get the oldest file in the folder (common scenario when deleting old logs) you can try this

   public static string FindOldestFileInFolder(string path)
   {
        return Directory.Exists(path) && Directory.GetFiles(path).Count() > 0 ? 
               Directory.EnumerateFiles(path)
               .Select(i => new FileInfo(i))
               .OrderByDescending(i => i.LastAccessTime).FirstOrDefault()
               .FullName : null;
   }

If you want to compare two files and get identical lines this may be useful to you

   public static IEnumerable<string> FindIdenticalLinesInTwoFiles(string filePath1, string filePath2)
    {
        if (File.Exists(filePath1) && File.Exists(filePath2))
        {
            return File.ReadAllLines(filePath1).Where(i => !string.IsNullOrEmpty(i))
                   .Intersect(File.ReadAllLines(filePath2).Where(i => !string.IsNullOrEmpty(i)));
         }

       return null;
    }

When collecting system information this function may be useful as well. It simply gets all extensions of the files in the directory and counts number of files associated with them.

 public static Dictionary<string, int> ListAndCountTheNumberOfDifferentFileExtensions(string path) 
   {
       return Directory.EnumerateFiles(path)
              .Select(i => new FileInfo(i))
              .GroupBy(i => i.Extension)
              .OrderByDescending(i => i.Count())
              .ToDictionary(i => i.Key, i => i.Count());            
    }

As you can see using LINQ is so easy that allows you to focus more on the business problems and less on coding itself.

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...

Extension methods in C#

Extension methods enable you to add your own methods to already existing system types without deriving from those types. Extension methods are always static but they are called as a instance methods on the extended types. We can extend types like string, double, DateTime etc. as well as LINQ queries which already are extensions of IEnumerable type.

Extended types can be used as a helper methods that you can compile and use in all your projects.

Lets start with the simple string extensions. First example simply checks if string has a value. The second one strips html tags from the string.

    /// <summary>
    /// Determines whether this instance of string is not null or empty.
    /// </summary>
    public static bool HasValue(this string text)
    {
        return !string.IsNullOrEmpty(text);
    }

    /// <summary>
    /// Strips html tags from the string
    /// </summary>
    public static string HtmlStrip(this string input)
    {
        input = Regex.Replace(input, "<style>(.|\n)*?</style>", string.Empty);
        input = Regex.Replace(input, @"<xml>(.|\n)*?</xml>", string.Empty);
        return Regex.Replace(input, @"<(.|\n)*?>", string.Empty);
    }   

Similar is with the double extensions

    /// <summary>
    /// Rounds the value to last 10s
    /// </summary>
    public static double RoundOff(this double i)
    {
        return ((double)Math.Round(i / 10.0)) * 10;
    } 

The sample below is very useful when displaying dates. It displays friendly string with the time left to an event, it extends DateTime type.

 public static string ToDateLeftString(this DateTime input)
    {
        var oSpan = DateTime.Now.Subtract(input);
        var TotalMinutes = oSpan.TotalMinutes;
        var Suffix = " ago";

        if (TotalMinutes < 0.0)
        {
            TotalMinutes = Math.Abs(TotalMinutes);
            Suffix = " from now";
        }

        var aValue = new SortedList<double, Func<string>>();
        aValue.Add(0.75, () => "less than a minute");
        aValue.Add(1.5, () => "about a minute");
        aValue.Add(45, () => string.Format("{0} minutes", Math.Round(TotalMinutes)));
        aValue.Add(90, () => "about an hour");
        aValue.Add(1440, () => string.Format("about {0} hours", Math.Round(Math.Abs(oSpan.TotalHours)))); // 60 * 24
        aValue.Add(2880, () => "a day"); // 60 * 48
        aValue.Add(43200, () => string.Format("{0} days", Math.Floor(Math.Abs(oSpan.TotalDays)))); // 60 * 24 * 30
        aValue.Add(86400, () => "about a month"); // 60 * 24 * 60
        aValue.Add(525600, () => string.Format("{0} months", Math.Floor(Math.Abs(oSpan.TotalDays / 30)))); // 60 * 24 * 365 
        aValue.Add(1051200, () => "about a year"); // 60 * 24 * 365 * 2
        aValue.Add(double.MaxValue, () => string.Format("{0} years", Math.Floor(Math.Abs(oSpan.TotalDays / 365))));

        return aValue.First(n => TotalMinutes < n.Key).Value.Invoke() + Suffix;
    } 

The last example extends the IEnumerable type so we are actually adding a new LINQ function.

    /// <summary>
    /// Selects the item with maximum of the specified value.
    /// </summary>
    public static T WithMax<T, TKey>(this IEnumerable<T> list, Func<T, TKey> keySelector)
    {
        return list.OrderByDescending(i => keySelector(i)).FirstOrDefault();
    } 

When testing above methods you will get following results

  static void Main(string[] args)
    {
        //DateTime extended method
        var myDate = DateTime.Now.AddDays(7);
        var dateLeft = myDate.ToDateLeftString(); //result: "6 days from now"

        //System.String extended method
        var myNoHtmlString = "<br><b>test</b>".HtmlStrip(); //result: "test"

        //or 
        var hasStringValue = "test string".HasValue(); //result: true

        //System.Double extension
        double myTo10sRoundedValue = (66.3).RoundOff(); //result: 70

        //Linq extensions
        List<int> list = new List<int>() { 1, 2, 3 }; 
        var max = list.WithMax(i => i); //result: 3
    }

I have included sample project below so you can do some testing yourself.
ExtensionMethods

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...

LINQ – filtering data structures

Using Language-Integrated Query (LINQ) has become very common in recent years as it is an easy way to retrieve data from various data structures eg. arrays. The code itself is also very clean and much shorter comparing to non LINQ implementations.

In this article I will show you how easy filtering data can be using LINQ.

Lets create client class first.

public class Client
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public IEnumerable
Addresses { get; set; } } public class Address { public string Street { get; set; } public string City { get; set; } public string Country { get; set; } }

Next we create Client data source with some dummy data

 public IEnumerable ClientDB
{
    get
    {
        var clients = new List();

        #region load dummy data
        clients.Add(new Client()
        {
            ID = 1,
            Name = "Client1",
            Addresses = new List
() { new Address() { Street = “street1”, City = “city1”, Country = “UK” }, new Address() { Street = “street2”, City = “city2”, Country = “US” } } }); clients.Add(new Client() { ID = 2, Name = “Client2”, Addresses = new List
() { new Address() { Street = “street1”, City = “city1”, Country = “IT” }, new Address() { Street = “street2”, City = “city2”, Country = “US” } } }); clients.Add(new Client() { ID = 3, Name = “Client3”, Addresses = new List
() { new Address() { Street = “street1”, City = “city1”, Country = “ES” }, new Address() { Street = “street2”, City = “city2”, Country = “US” } } }); #endregion return clients; } }

Now we can filter data from our structure before we can display it on the gridview. We only want to display clients with the UK address.

   
protected void Page_Load(object sender, EventArgs e)
    {
        var clients_With_UK_AddressOnly = ClientDB;

        //lets filter data
        clients_With_UK_AddressOnly = from client in ClientDB
                                        where client.Addresses.Count(a =&gt; a.Country == "UK") &gt; 0
                                        select client;

        //or you can do it shorter using "Any" function
        clients_With_UK_AddressOnly = ClientDB.Where(c =&gt; c.Addresses.Any(a =&gt; a.Country == "UK"));

        GridView1.DataSource = clients_With_UK_AddressOnly;
        GridView1.DataBind();
    }

As you can see when using LINQ, we can do a lot with the data in just one line of code. The code itself if less prone to errors and more elegant.

LINQ-data-filtering

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...