8

I have a registration page in my application. It has 3 states and 1 error state(If any error comes):

  1. Fill Basic Information
  2. Select Package
  3. Say Thanks
  4. Error

Now I want to use state pattern here. First I created a console application which is OK. Now I want to implement this logic in my MVC application but I am confused about the structure. I mean how many views, models and controller I need and where to place my logic.

jaco0646
  • 15,303
  • 7
  • 59
  • 83

2 Answers2

5

1 controller: RegistrationController

6 action methods:

  • GET+POST for Index (fill in basic info)
  • GET+POST for Package
  • GET for Thank you
  • GET for Error

This is rough code to make your mind going:

public class RegistrationController : Controller
{
    public ActionResult Index()
    {
        RegistrationState model = RegistrationState.Init();
        // just display the "Fill Basic Info" form
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(RegistrationState data)
    {
        // process data and redirect to next step
        this.TempData["RegState"] = data;
        if (!this.ModelState.IsValid || data.State == State.Error)
        {
            // error should handle provided state and empty one as well
            return RedirectToAction("Error");
        }
        return RedirectToAction("Package");
    }

    public ActionResult Package()
    {
        RegistrationState data = this.TempData["RegState"] as RegistrationState;
        if (data == null)
        {
            return RedirectToAction("Error");
        }

        // get packages and display them
        IList<Package> model = this.repository.GetPackages();
        return View(new Tuple.Create(data, model));
    }

    [HttpPost]
    public ActionResult Package(RegistrationState data)
    {
        // process data blah blah blah
    }

    // and so on and so forth
    ....
}

As you can see you still have to write some MVC-related code to act upon state changes. In my example everything's done in action methods. But action filters could be used as well. If you can't come up with a general action filter that can serve many different state objects then it's best to just write the code in action methods.

Another approach

If you know Asp.net MVC good enough you could take this a step further and write a state machine ControllerFactory that would work along with routing in a sense as:

{StateObjectType}/{State}

ControllerFactory would therefore be able to parse view data to a known state object type and pass execution to particular action. According to state. This would make it a specially state machine suited Asp.net MVC application.

The more important question is of course whether you can create the whole application with this pattern or are there just certain parts of it that should work like this. You could of course combine both approaches and provide appropriate routing for each.

Important notices

  1. You should be very careful how you define your error state, because entering invalid field data shouldn't result in error state but rather in data validation errors that actually display within the view beside the field with invalid data (ie. invalid date provided as 13/13/1313). Your error state should only be used for actual object state error that's not related to user input. What would that be is beyond my imagination.

    As mentioned in my comment you should check out some Asp.net MVC intro videos and you'll see how validation works in Asp.net MVC. Also rather simple stuff.

  2. State pattern of this kind is not something a regular Asp.net MVC developer would use, because it would most likely complicate code more than taking the normal approach. Analyse before you decide. Asp.net MVC is very clean code wise so adding additional abstraction over it may become confusing. And your domain model (state classes) would most likely have a much more complex code as simple POCOs with data annotations.

    In your case data validation would also be more complicated (when used with data annotations) because you object should be validated according to its state which may be different between states. POCO objects are always validated the same. This may mean that we may use more classes but they are smaller, simpler and easier to maintain.

Community
  • 1
  • 1
Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • 2
    Thank you Robert. But I have 1 more doubt about views. How many views I need here 1 or 4? –  Oct 05 '11 at 08:15
  • 2
    @Shared: 4 views all together. One for each state. But you should check some Asp.net MVC introduction videos that would make this thing clear to you. Asp.net MVC has a very short learning curve because it's so simple and pure so it shouldn't take you too long to know it enough to make this work. It will also make it obvious why you need a view for each state. I suppose you know Asp.net WebForms because there would most likely be just a single aspx page for all these... – Robert Koritnik Oct 05 '11 at 08:24
  • @Sharad: I edited my answer a bit, because you actually need just 6 action methods and not 8 as I first wrote. But you do need 4 views. – Robert Koritnik Oct 05 '11 at 08:32
  • @Sharad: I added some important info to my answer as well to make you step back a little and think about your approach from a developer's and maintainability perspective. – Robert Koritnik Oct 05 '11 at 08:42
0

I think you are confusing states. Examples of state are:

  1. Awaiting for a user to register
  2. User registered successfully
  3. User didn't register successfully

Now each of these states would have a page:

  1. localhost:8034/Register
  2. localhost:8034/Register/Success
  3. localhost:8034/Register/Failure

If user can't register because they left some fields empty, they will be in the first state and you will have to display some validation messages.

Because of this, as the minimum I'll have a controller called Register and the following action methods:

  1. Index() GET/POST
  2. Success() GET
  3. Failure() GET