Search code examples
asp.netfubumvc

fubumvc - simple forms validation using IFailureValidationPolicy


I've been trying to implement form validation correctly and a discussion on fubu mailing list has been the most helpful (http://groups.google.com/group/fubumvc-devel/browse_thread/thread/d54b135fe0254653/12180cd86e9dc50b). I'm still not entirely clear on certain points, I'm a newbie so I'm going through some yak shaving.

It seems like the example given in the discussion performed the validation within the controller itself using IsValid(model).

I'm trying to avoid this by decorating my input model with validation attributes such as Required and then use the validation configuration to Transfer on failure (via a policy).

this.Validation(x => {
                            x.Actions
                                .Include(call => call.HasInput && call.InputType().Name.EndsWith("Input"));

                            x.Failures                                    
                                .ApplyPolicy<AccountValidationFailedPolicy>();
                        });

And here's the class that implments the policy:

public class AccountValidationFailedPolicy : IValidationFailurePolicy {

    public bool Matches(ValidationFailure context) {
        return (context.InputType() == typeof (RegisterAccountInput));
    }

    public void Handle(ValidationFailure context) {
        var incomingRequest = (RegisterAccountInput) context.InputModel;

        var failedValidation = new RegisterationFailedNotification {
            CVV = incomingRequest.CVV,
            AcceptTerms = incomingRequest.AcceptTerms,
            Countries = incomingRequest.Countries,
            PhoneNumber = incomingRequest.PhoneNumber,
            PIN = incomingRequest.PIN
        };

        FubuContinuation.TransferTo(failedValidation);
    }
}

Handle simply tries to Transfer to another action via a new model, copying the values into the new model so that I can redisplay them again on the form.

I must be doing something wrong here, because it's not transferring anywhere. I have a class with this method which I was hoping would handle it.

public AccountViewModel New(RegisterationFailedNotification notification) { .... }

Am I on track here, or is there something fundamental that I'm not getting? Perhaps a policy is not the thing to do here?


Solution

  • @stantona

    The policy mechanism will work here. I'll spare you the details about how I plan to make this simpler (very soon), and note that your use of FubuContinuation.TransferTo simply creates a FubuContinuation -- it doesn't execute it.

    Here's what you need:

    public class AccountValidationFailedPolicy : IValidationFailurePolicy {
    private readonly IFubuRequest _request;
    private readonly IValidationContinuationHandler _handler;
    
    public AccountValidationFailedPolicy(IFubuRequest request, IValidationContinuationHandler handler) {
        _request = request;
        _handler = handler;
    }
    
    public bool Matches(ValidationFailure context) {
        return (context.InputType() == typeof (RegisterAccountInput));
    }
    
    public void Handle(ValidationFailure context) {
        var incomingRequest = (RegisterAccountInput) context.InputModel;
    
        var failedValidation = new RegisterationFailedNotification {
        CVV = incomingRequest.CVV,
        AcceptTerms = incomingRequest.AcceptTerms,
        Countries = incomingRequest.Countries,
        PhoneNumber = incomingRequest.PhoneNumber,
        PIN = incomingRequest.PIN
        };
    
        var continuation = FubuContinuation.TransferTo(failedValidation);
        _request.Set(continuation);
    
        _handler.Handle();
    }
    }