Skip to content

Instantly share code, notes, and snippets.

@andrei-m-code
Forked from lorddev/IBusinessRules.cs
Created June 17, 2016 13:26
Show Gist options
  • Save andrei-m-code/05ce29e6da418130ef24f0f892789eaa to your computer and use it in GitHub Desktop.
Save andrei-m-code/05ce29e6da418130ef24f0f892789eaa to your computer and use it in GitHub Desktop.
Ideas on a business rules implementation
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Devlord.Utilities
{
/// <summary>
/// Use for designing a business rule where conditions are evaluated and the actions are executed based on the evaluation.
/// Rules can be chained by setting the "Action" as another business rule.
/// </summary>
/// <typeparam name="TConditions">The type of the condition or conditions.</typeparam>
/// <typeparam name="TAction">The type of the action or actions to be executed.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <seealso cref="SnapMD.Core.Interfaces.IBusinessRule" />
internal interface IBusinessRule<TConditions, TAction, TResult> : IBusinessRule
where TConditions : IRuleCondition where TAction : IRuleExecution<TResult>
{
IEnumerable<TAction> Action { get; set; }
IEnumerable<TConditions> Conditions { get; set; }
}
internal interface IBusinessRule
{
IEnumerable Results { get; }
RuleState State { get; }
Task Execute();
}
public enum RuleState
{
None,
Initialized,
InProgress,
FailedValidation,
Faulted,
Completed
}
public interface IRuleCondition
{
bool Validate();
}
public interface IRuleExecution<TResult>
{
Task<TResult> Execute();
}
public abstract class RuleBase<TCondition, TAction, TResult> :
IBusinessRule<TCondition, TAction, TResult> where TCondition : IRuleCondition
where TAction : IRuleExecution<TResult>
{
public ICollection<TResult> Results { get; } = new List<TResult>();
public IEnumerable<TCondition> Conditions { get; set; }
public IEnumerable<TAction> Action { get; set; }
IEnumerable IBusinessRule.Results => Results;
public RuleState State { get; private set; } = RuleState.Initialized;
public async Task Execute()
{
State = RuleState.InProgress;
try
{
var isValid = true;
foreach (var item in Conditions)
{
isValid &= item.Validate();
if (!isValid)
{
State = RuleState.FailedValidation;
return;
}
}
foreach (var item in Action)
{
var result = await item.Execute();
Results.Add(result);
}
}
catch (Exception)
{
State = RuleState.Faulted;
throw;
}
State = RuleState.Completed;
}
}
public class TestRule1 : RuleBase<FakeConditionAlwaysReturnsTrue, WriteHelloAction, string>
{
public TestRule1()
{
Conditions = new[] { new FakeConditionAlwaysReturnsTrue() };
Action = new[] { new WriteHelloAction() };
}
}
public class FakeConditionAlwaysReturnsTrue : IRuleCondition
{
public bool Validate()
{
return true;
}
}
public class WriteHelloAction : IRuleExecution<string>
{
public async Task<string> Execute()
{
return await Task.Run(() => "hello world!");
}
}
public static class Program
{
public static async Task Main()
{
IBusinessRule rule = null;
try
{
rule = new TestRule1();
await rule.Execute();
foreach (string item in rule.Results)
{
// Prints "hello world!"
Console.WriteLine(item);
}
}
catch (Exception ex)
{
if (rule != null && rule.State == RuleState.Faulted)
{
throw new Exception("Error in rule execution", ex);
}
throw;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment