The S#arp framework: still on the web assembly
Ok, it seems like I’ve missed a couple of interesting classes defined on the SharpArch.Web assembly in my last post. It’s time to fix this and today we’re going to talk about the MvcValidationAdapter and the ValidatableModelBinder classes. Let’s get started with the MvcValidationAdapter class…
As you know, S#arp has its own validation thing. We also know that MVC has some validation support into it. The MvcValidationAdapter exists for letting you easily map S#arp validation errors into the MVC validation model. Here’s a quick example of its usage (taken from the EmployeesController, Northwind sample):
public ActionResult Create(Employee employee) {
if (employee.IsValid()) {
employeeRepository.SaveOrUpdate(employee);
TempData["message"] = employee.FullName + " was successfully created.";
return RedirectToAction("Index");
}
MvcValidationAdapter.TransferValidationMessagesTo(ViewData.ModelState,
employee.ValidationResults());
return View();
}
Internally, the method will simply populate the ModelState with the errors found return by the ValidationResults method:
public static ModelStateDictionary TransferValidationMessagesTo(
ModelStateDictionary modelStateDictionary, IEnumerable<IValidationResult> validationResults) {
Check.Require(modelStateDictionary != null, "modelStateDictionary may not be null");
Check.Require(validationResults != null, "invalidValues may not be null");
foreach (IValidationResult validationResult in validationResults) {
Check.Require(validationResult.ClassContext != null,
"validationResult.ClassContext may not be null");
string key = validationResult.ClassContext.Name +
(!string.IsNullOrEmpty(validationResult.PropertyName)
? "." + validationResult.PropertyName
: "");
modelStateDictionary.AddModelError(key, validationResult.Message);
modelStateDictionary.SetModelValue(key, new ValueProviderResult(null, null, null));
}
return modelStateDictionary;
}
As you can see, each IValidationResult is transformed into an error entry that gets added to the model state dictionary.
We can take this one step ahead an integrate validation with the binding by extending the DefaultModelBinder class (which is used by default to perform the bindings). The ValidatableModelBinder overrides the OnModelUpdated and OnPropertyValidated methods. Here’s the code for those methods:
public class ValidatableModelBinder : DefaultModelBinder {
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
IValidatable model = bindingContext.Model as IValidatable;
if (model != null) {
if (! model.IsValid()) {
foreach (IValidationResult validationResult in model.ValidationResults()) {
bindingContext.ModelState
.AddModelError(validationResult.ClassContext.Name +
(!string.IsNullOrEmpty(validationResult.PropertyName)
? "." + validationResult.PropertyName
: ""),
validationResult.Message);
}
}
}
}
protected override void OnPropertyValidated(ControllerContext controllerContext,
ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value) {
// Do nothing
}
}
As you can see, the code is really similar to the one we have on the TransferValidationMessagesTo method (of the MvcValidationAdapter class) presented earlier. Using this binder means that you’ll get automatic translation from the S#arp entities (which support validation) into the model state error entries. If you want to use this binder, then you’ll need to register it and associate it with a type.
And that’s it for today. Keep tuned for more on the S#arp framework.