Hello Coding Buddy! π Welcome to the continuation of my previous article about getting started with Building A JSON Rules Engine from Scratch with MSRulesEngine β Part 1. If you havenβt checked it out. Please do so before continuing with current article.
In this Article, we will modify our MSRuleEngine to load the JSON rules from Database (Sqlite) using EF core and inject them into the RulesEngine Wrapper. This is to demonstrate that the rules can be saved from database and can be loaded when needed in JSON format to be used by your application.
Note: The JSON Rules can be saved in the DB in many ways. You can use the built-in RulesEngine.Models as your DB models or save those rules as JSON inside one of your table columns etc. In this article I am taking the second approach to keep it simple for our learning. I will create another article explaining how to use built-in models to achieve the same.
So, now we had setup some expectations we can dig into actual implementation of this integration. Let's implement/learn it together.
Step by Step Instructions:
- Download the base code from Github Repo.
- Install below packages to your downloaded console application.
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
- Modify your
Arcade.cs
class under Models folder as shown below.
namespace MsRulesEngine.Models;
public class Arcade {
public string Name { get; set; } = string.Empty;
public long Id { get; set; }
public string Workflows { get; set; } = string.Empty;
}
- Create a class named
ArcadeDbContext.cs
underDBContext
folder. Then add below code to it. You might get some errors as we havenβt added model configurations to our project yet. We will do it in the next steps.
using Microsoft.EntityFrameworkCore;
using MsRulesEngine.DBConfigurations;
namespace MsRulesEngine.DBContext;
public class ArcadeDbContext : DbContext
{
public string DbPath { get; private set; }
public ArcadeDbContext()
{
DbPath = Path.Combine(Environment.CurrentDirectory, "Database", "ArcadeDb.db");
}
public DbSet<Game> Games { get; set; }
public DbSet<Arcade> Arcades { get; set; }
#region Required
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ArcadeDbConfiguration).Assembly);
string filePath = Path.Combine(Environment.CurrentDirectory, "RulesFiles", "DiscountRules.json");
string jsonString = File.ReadAllText(filePath);
Arcade arcade = new()
{
Name = "Arcade1",
Id = 1,
Workflows = jsonString
};
Game game = new()
{
Title = "Halo",
Genre = "Action",
Id = 1,
Platform = "PlayStation",
GamingStudio = "Sony",
Price = 59.99m
};
modelBuilder.Entity<Game>().HasData(game);
modelBuilder.Entity<Arcade>().HasData(arcade);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlite($"Data Source={DbPath}");
}
#endregion
}
- Now create
Fluentconfigurations
for the Arcade and Game Models by creatingArcadeDbConfiguration.cs
andGameDbConfiguration.cs
files underDBConfigurations
folder in your project. Add below code to those two files.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace MsRulesEngine.DBConfigurations;
public class GameDbConfiguration : IEntityTypeConfiguration<Game>
{
public void Configure(EntityTypeBuilder<Game> builder)
{
builder
.HasKey(a => a.Id);
builder.Property(a => a.Title);
}
}
// Arcade Configurations
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace MsRulesEngine.DBConfigurations;
public class ArcadeDbConfiguration : IEntityTypeConfiguration<Arcade>
{
public void Configure(EntityTypeBuilder<Arcade> builder)
{
builder
.HasKey(a => a.Id);
builder.Property(a => a.Workflows)
.HasMaxLength(4000);
}
}
- Now on your project folder create a new class called
EFCoreDemo.cs
. Add below code to it.
using Microsoft.EntityFrameworkCore;
using MsRulesEngine.DBContext;
using RE = RulesEngine;
namespace MsRulesEngine;
public class EFCoreDemo
{
public static async Task Run()
{
ArcadeDbContext db = new();
db.Database.EnsureCreated();
var dbArcade = db.Arcades.FirstOrDefault();
var games = db.Games.AsNoTracking().ToArray();
var workflows = JsonSerializer.Deserialize<Workflow[]>(dbArcade!.Workflows);
RE.RulesEngine rulesEngine = new(workflows);
var resultList = await rulesEngine.ExecuteAllRulesAsync("GameDiscount", games);
foreach (var result in resultList)
{
Console.WriteLine($"Rule: {result.Rule.RuleName}, Result: {result.IsSuccess}, Message: {result.ExceptionMessage}");
}
}
}
- Modify
program.cs
as shown below
// See https://aka.ms/new-console-template for more information
using MsRulesEngine;
// await SimpleJsonRuleDemo.Run();
await EFCoreDemo.Run();
- Execute the
program.cs
and you will see the below output.
Conclusion:
Have you observed how simple it is to load the rules from our Sqllite database columns and pull them using EF core on demand during the application runtime. This is another way of storing these JSON based rules file. There are other ways to save the JSON files, I will be creating articles on them as well. So, stay tuned for many other related articles! See you next time! Also, before I forget here is the link to GitHub Repo.
Top comments (2)
You could use
builder.Property(c => c.customer)
.HasConversion(c => JsonConvert.SerializeObject(c),
c => JsonConvert.DeserializeObject(c));
Good Suggestion. I can implement it.