Last active
June 17, 2016 13:26
-
-
Save lorddev/d4a953a5b0f8021d7f36d68959930a68 to your computer and use it in GitHub Desktop.
Ideas on a business rules implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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