NCommons Rules Engine
I recently decided to invest some time in learning how my team might leverage the MvcContrib rules engine for our projects at work. I discovered this feature after browsing the CodeCampServer source which seems to be the only publicly available example of the rules engine in use. I was impressed at how clean the controller actions were as a result of leveraging this feature in conjunction with some additional infrastructure sugar the CodeCampServer adds.
While I liked the capabilities of the MvcContrib rules engine overall, there were a few aspects I wanted to change. One of those things was the coupling to the validation strategy provided by the rules engine and another was the need for a bit of additional infrastructure code to help parse the results when mapping validation errors back to their corresponding UI elements.
I also recently became aware of the Fluent Validation library by Jeremy Skinner and thought to myself: “I wonder how long it would take to just create my own rules engine leveraging the Fluent Validation framework”, so I sat down last weekend to find out. Well, after getting something up and going, I thought I might as well share my results. I should note that given my effort was inspired by the MvcContrib rules engine, some of the same concepts are reflected in my effort (though perhaps with a more naive implementation).
Overview
The basic rules engine works as follows:
- A user invokes some Controller action.
 - The Controller takes the action’s parameter and invokes the RulesEngine.Process() method.
 - The RulesEngine invokes an injected implementation of IRuleValidator.Validate() on the object.
 - The IRulesValidator returns a RuleValidationResult denoting the status of the validation as well as containing any validation error messages.
 - The RulesEngine uses the Common Service Locator to find implementations of ICommand
where T matches the type of the object.  - The implementations of ICommand
are executed and any results accumulated.  - The RulesEngine returns a ProcessResult which contains the process status and any validation messages and return items.
 - The Controller uses the status to determine which action to display. In the event of a validation failure, the error messages are added to the ModelState with their associated property names.
 
Here is an example usage:
[HttpPost] 
public ActionResult Create(ProductInput productInput) 
{ 
	ProcessResult results = _rulesEngine.Process(productInput);
 
	if (!results.Successful) 
	{ 
		CopyValidationErrors(results); 
		return View(productInput); 
	}
 
	return RedirectToAction("Index"); 
} 
void CopyValidationErrors(ProcessResult results) 
{ 
	foreach (RuleValidationFailure failure in results.ValidationFailures) 
	{ 
		ModelState.AddModelError(failure.PropertyName, failure.Message); 
	} 
}
In an example application I’ve included with the source, I created an implementation of the IRulesValidator which adapts to the Fluent Validation library:
public class FluentValidationRulesValidator : IRulesValidator 
{ 
	public RuleValidationResult Validate(object message) 
	{ 
		var result = new RuleValidationResult(); 
		Type validatorType = typeof (AbstractValidator<>).MakeGenericType(message.GetType()); 
		var validator = (IValidator) ServiceLocator.Current.GetInstance(validatorType); 
		ValidationResult validationResult = validator.Validate(message);
		if (!validationResult.IsValid) 
		{ 
			foreach (ValidationFailure error in validationResult.Errors) 
			{ 
				var failure = new RuleValidationFailure(error.ErrorMessage, error.PropertyName); 
				result.AddValidationFailure(failure); 
			} 
		}
		return result; 
	} 
}
This uses the Common Service Locator to find types closing the Fluent Validation AbstractValidator
Mapping
I also included the ability to map UI types to domain types using a library such as AutoMapper. To express this as an optional feature, I created a MappingRulesEngine which has a dependency on an IMessageMapper. At first I went back and forth between expressing an IMessageMapper as an optional dependency to the RulesEngine, but I don’t really like property injection and the notion of using constructor injection for optional dependencies was a bit distasteful, so using inheritance felt like the cleanest and most expressive option.
The MappingRulesEngine uses the Common Service Locator to find a type closing AssociationConfiguration
public class ProductInputAssociationConfiguration : AssociationConfiguration<ProductInput> 
{ 
	public ProductInputAssociationConfiguration() 
	{ 
		ConfigureAssociationsFor<Product>(x => 
			{ 
				x.For(output => output.Id).Use(input => input.Id); 
				x.For(output => output.Description).Use(input => input.Description); 
				x.For(output => output.Price).Use(input => input.Price); 
			}); 
	} 
}
That’s about it. You can get the source at https://github.com/derekgreer/ncommons.
