Using FluentValidation with FubuMvc

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);