Create the validation behavior
public class ValidationBehaviour<T> : BasicBehavior where T : class { private readonly IContinuationDirector continuationDirector; private readonly BehaviorGraph behaviorGraph; private readonly IFubuRequest fubuRequest; private readonly IValidator<T> validator;
public ValidationBehaviour(IContinuationDirector continuationDirector, BehaviorGraph behaviorGraph, IFubuRequest fubuRequest, IValidator<T> validator) : base(PartialBehavior.Ignored) { this.continuationDirector = continuationDirector; this.behaviorGraph = behaviorGraph; this.fubuRequest = fubuRequest; this.validator = validator; }
protected override DoNext performInvoke() { var inputModel = fubuRequest.Get<T>(); var validationResult = validator.Validate(inputModel); if (validationResult.IsValid) { return DoNext.Continue; } fubuRequest.Set(validationResult); var actionCall = GetActionCallFromBehaviorGraph(); continuationDirector.TransferToCall(actionCall); return DoNext.Stop; }
private ActionCall GetActionCallFromBehaviorGraph() { return behaviorGraph .Behaviors .Where(chain => chain.FirstCall().HandlerType.Namespace == typeof(T).Namespace && chain.Route.AllowedHttpMethods.Contains(WebRequestMethods.Http.Get)) .Select(chain => chain.FirstCall()) .First(); } }
Tell FubuMvc when to use the validation behavior
public class ValidationConfiguration : IConfigurationAction
{
public void Configure(BehaviorGraph graph)
{
graph.Actions()
.Where(x \=> x.HasInput && ObjectFactory.Model.HasDefaultImplementationFor(typeof(IValidator<>).MakeGenericType(x.InputType())))
.Each(x \=> x.AddBefore(new Wrapper(typeof(ValidationBehaviour<>).MakeGenericType(x.InputType()))));
}
}
Add an HtmlConvention to display the error messages
HtmlConvention(x => x.Editors.Always.Modify((request, tag) => { var fubuRequest = request.Get<IFubuRequest>(); var validationResult = fubuRequest.Get<ValidationResult>(); if (validationResult.IsValid) return; var ul = new HtmlTag("ul"); var liTags = validationResult.Errors.Where(error => error.PropertyName == request.Accessor.InnerProperty.Name).Select(vf => new HtmlTag("li", li => li.Text(vf.ErrorMessage))); ul.Append(liTags); tag.Append(ul); }));
Apply the Validation Configuration
ApplyConvention<ValidationConfiguration>();
Wire up the IContinuationDirector and Validators
FubuApplication.For<ConfigureFubuMvc>().StructureMapObjectFactory(container => { container.Scan(scanner => { scanner.TheCallingAssembly(); scanner.WithDefaultConventions(); scanner.ConnectImplementationsToTypesClosing(typeof(IValidator<>)); }); container.For<IContinuationDirector>().Use<ContinuationHandler>(); }) .Bootstrap(RouteTable.Routes);
