views:

16

answers:

2

Overview

I have a payment page where I allow the user to select a payment method, either credit card or check. I have a form for each of these payment methods. I did not want to create a separate page for each of these methods for UI purposes, so I use a [div] for each form and toggle their display with jQuery.

Problem

Each of the payment methods has its own set of validation rules. I want to be able to apply model validation to only the payment method that was selected and submitted by the user. In order to do validation, I am required to POST to the same controller action, so submitting to different actions is not an option.

Approaches

I have considered the following approaches:

  1. Partial Validation based on incoming values, as described here: http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/. My issue with this approach is the security implication, and as this is a relatively small app, I don't have a separate domain layer as the author of the article suggests.
  2. Create separate models for each payment method, and then overload the controller [HttpPost] action with a different model parameter. I tried this but the compiler complains that the action is ambiguous, even though I have something like this

    [HttpPost]
    public ActionResult Pay(CreditCardPaymentModel model) {...}

    [HttpPost]
    public ActionResult Pay(CheckPaymentModel model) {...}

  3. Use separate controller actions to handle the individual form posts and use TempData to set the validation messages and redirect back to the form page to display the messages. I really don't like this option as it feels clunky, and I don't like using TempData for anything other than simple messages.

I would welcome any suggestions on the best way to handle such a situation cleanly and efficiently.

A: 

I would go with option 2, as it gives you a nice, clean separation between payment models and concrete model classes (I always go for strongly typed solutions).

Option 2 will also be easy to unit test...

Jakub Konecki
Jakub, I also liked Option 2 the best, but I cannot get it to work the way I thought it would. The compiler spits out an error when I try to create the two overloaded controller actions. Have you been able to get this to work?
XSaint32
Sorry, I haven't noticed that you controller actions have the same name. You will have to make them unique, ie. PayByCard, PayByCheque, etc.
Jakub Konecki
A: 

I'd go for the strategy 3.

When you toggle form views with jQuery you can also replace the post url of the form. This way it can easily be handled by different controller methods each with their own validation logic.

One other option (not the one I like) is to create a merged model for both payment option. Upon instantiation of that model you can probably easily distinguish what form was active. Or you can also set some hidden value with jQuery to indicate the active form view.

P.S. With #2 it is difficult to tell which model instantiation will work out until the framework attempts to instantiate one and if it fails another. This is not quite straightforward and the framework was not built to be that intelligent and bring some initiative into the process.

Developer Art
Art, I agree with your comment regarding the "intelligence" of the framework. Regarding the merged payment option, the problem I am having is that ALL model validation is firing on the submit, regardless of which form was active. So that leaves me with some messy cleanup (ie - looping through the ModelState), and not being able to use the out-of-the-box ValidationSummary, etc.
XSaint32