up vote 0 down vote favorite

In my MVC application I have a problem with passing data from view to controller. I have fairly complex domain classes:

public class TaskBase : PersistableObject
{
    public virtual TaskCategory Category { get; set; }
    public virtual IList<TaskNote> Notes { get; set; }
    public virtual string TaskTitle { get; set; }
    public virtual string TaskBody { get; set; }
    public virtual DateTime? CreationTime { get; set; }
    public virtual User CreatedBy { get; set; }
    public virtual int CompletionRatio { get; set; }
}

public class MainTask : TaskBase
{
    public virtual IList<TaskBase> ChildTasks { get; set; }
    public virtual User AssignedTo { get; set; }
    public virtual IList<TaskHistory> History { get; set; }
}

public class TaskFormModel : ViewDomainBase
{
    public MainTask Task { get; set; }
    public LoginForm LoginInfo { get; set; }
}

And in my view I want to pass an instance of TaskFormModel to the controller.

<%= Html.ActionLink<TaskController>("Edit Task", (x) => x.Edit(new TaskFormModel() { Task = item, LoginInfo = Model.LoginInfo }))%>

And here is the controller action:

public ActionResult Edit (TaskFormModel taskInfo)
{
    return View(ViewPageName.TaskDetailsForm, task.Task);
}

In this action method taskInfo comes null even if I pass non-null instance from view. I think I have a binding problem here. I think, writing custom model binder requires every property to be converted and also when new fields added then binder class should also be changed, so I don't want custom model binder to do this. Is there any other way to pass data to controller in this scenario? Or could custom model binder can be coded so that less code written and also when new properies are added binder class will not need to be changed?

Edit After Comments: What I am trying to achieve is basically to pass an instance from one view to another view, without querying repository/db in my controller's action.

link|flag

@arh, why do you not want to go back to the db when you are passing the object? personally I'd prefer that approach as it keeps everything seperate. I'd pass around only the id. Lot's less traffic too. – griegs Dec 20 '09 at 23:49

2 Answers

up vote 3 down vote accepted

First version of answer:

Your GET edit method should be like:

public ActionResult Edit (int id)
{
    var model = taskRepository.GetTaskEditModel(id);
    return View(ViewPageName.TaskDetailsForm, model);
}

and ActionLink:

<%= Html.ActionLink("Edit Task", "Edit", "Task", new { model.Task.id })%>

If you want to pass complex objects to controller, you should wrap them up in html form and pass to POST action.

link|flag
I believe @arch's edit action is correct. He's passing the entire object to the ActionResult. I've done exactly the same before. What's not clear in the question is how the task is given to the view in the first place. Whether he passes the object to the edit action or does a lookup. If it's a lookup then your answer stands, if not then all's good with his. – griegs Dec 20 '09 at 22:15
Question is not clear enough. It would be good to know what author is trying to achieve. He could also decorate action with [HttpGet] or [HttpPost] attribute. – LukLed Dec 20 '09 at 22:20
Yeah agreed. He could decorate with HttpPost but in the code he's provided it's not required but like you say, it's kinda unclear at this point. – griegs Dec 20 '09 at 22:27
ActionLink usage suggests it is GET method. Passing complex object to GET method doesn't look here like a good idea. – LukLed Dec 20 '09 at 22:31
Look I agree with you 100%. I'm just saying that in this case I don't think it's the issue. I do believe however that he needs to wrap it all in a Form but I think the main issue here, and the reason it's not working, is "new TaskFormModel() { Ta..." He should drop the (). – griegs Dec 20 '09 at 22:34
show 7 more comments
up vote 0 down vote

In my opinion you are doing something wrong. As I understand: you are trying to instantiate a new object, pass it to browser and get it back. well you cant.

If object you want to edit exists already in your storage, then you should alter your ActionLink to reference it by id, and instantiate it inside your Edit action.

Take a look at default strongly typed index views created by tooling.

link|flag

Your Answer

 
or
never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.