views:

766

answers:

4

Situation: In some project management software written in asp.net I have a create project page (working fine). I need to add to this the ability to add tasks from a list of templates to this project pre-creation BUT the list of available tasks is dependent on some values sitting in the create form.

My abstract solution is this:

  • I have a "Create" view and an "Add Tasks" View - both strongly typed to a composite viewModel defined in the controller
  • My Create method checks which button was used to call it - if the button was "Add Tasks" it then renders the AddTasks view, passing the model in from the create view, again all in the same controller.
  • The AddTasks View posts to the Create view with one of two buttons, one loads the view and the other causes an actually DB save.

My Problem is this:

  • The different views use different properties of the same model, but in passing this model between them, the data is reset (in any case reload or save).
  • I am guessing this is happening from auto binding of data - though I thought fields not present on the form would not overwrite existing model data passed down.
  • There is hardly any code in the controller manipulating the model at present - It is only passed from view to view in these cases.

This is the controller code:

    // POST: /Project/Create/<viewModel>
    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "Id,id")] ProjectViewModel model)
    {
        if (model.SubmitValue == "Create")
        {
            try
            {
                model.Project.Id = Guid.NewGuid();
                model.Save(this.User.Identity.Name);
                return this.RedirectToAction("Details", new {id = model.Project.Id});
            }
            catch (Exception e)
            {
                this.ModelState.AddModelError(e.ToString(), e.ToString());
            }
            return View(model);
        }

        if(model.SubmitValue == "AddTasks")
        {
            return this.View("AddTasks",model);
        }

        return this.View(model);

    }


    //POST: /Project/AddTasks/ + model
    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult AddTasks([Bind(Include = SelectedCarrierTasks")]ProjectViewModel model)
    {
        return View(model);
    }

The Question is: How do I maintain the state of the model across these views until it finally save it?

I would prefer to avoid any hackish (TempData) or JS dependant solutions, but I am not closed to these if they are really the best solution.

Thanks, Adam Tolley

+1  A: 

The problem is that when you display the add tasks view you're not providing fields for your "Project" object therefore the ModelState loses the data related to the project, you will need to provide this fields to ensure you're not loosing that data.

You don't need to display this fields they can be of type hidden and they will preserve the value. Just make sure that if you will be binding to a view model you will need to name this fields correctly like this Model.Project.Property.

jgarcia
So I can persist it by storing it client side in hidden fields, is there a way to not depend on client side storage? It feels a bit strange to laden a page and browser with a fairly large model like that, just for the sake of preserving across methods/views in the very same controller. Thanks for your input
Adam Tolley
+2  A: 

One simple solution is to persist the ViewModel object in a Session variable and bind the View from this source.I ts certainly not the most elegant solution. Another option, and probably less elegant one is persist this model data in the database, with some temporary/unsaved flag.

Oleiro
A: 

I can't comment on other peoples questions at the moment, but the only real option is the session if you want to persist an objects state during web requests, or serializing it and placing it in a hidden field.

Or a final option would be to change the way your pages work so you can save the object after each request...

If your using nHibernate then you might want look into the Conversations pattern, but this just essentially saves the nHibernate session into the asp.net session anyway...

theouteredge
I'll mark this as an answer as it is the most complete set of options and includes the NHibernate approach (though I am stuck with EF1 at the moment).
Adam Tolley
A: 

Perhaps I am trying to solve the wrong problem (ala Bruce Eckel). I am going to try to move to a structure that needs this sort of fuzzy boundary less. I don't want to adopt a REST paradigm only to shoe-horn it into a stateful application.

Possibly these controls belong on the same page, and I can use some JQuery goodness to put in a tab pane for easiness on the eyes.

Thanks to those who answered, I found each useful and will try to remember to up-vote them as soon as I have some more rep.

Adam Tolley