views:

53

answers:

1

I have an ASP.Net MVC Controller with a 'MapColumns' action along with a corresponding ViewModel and View.

I'm using the defaultModelBinder to bind a number of drop down lists to a Dictionary in the ViewModel. The view model also contains an IList field for both source and destination columns which are used to render the view.

My question is what to do when validation fails on the Post call to the MapColumns action?

Currently the MapColumns view is returned with the ViewModel resulting from the default binding. This contains the Dictionary values but not the two lists used to render the page. What is the best way to re-provide these to the view?

I can set them explicitly after failed validation, but if obtaining these values (via GetSourceColumns() and GetDestinationColumns() in the example) carries any overhead this doesn't seem ideal. What I am looking for is a way to retain these lists when they are not bound to the model from the view.

Here is some code to illustrate:

public class TestViewModel
{
    public Dictionary<string, string> ColumnMappings { get; set; }

    public List<string> SourceColumns;
    public List<string> DestinationColumns;
}

public class TestController : Controller
{
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult MapColumns()
    {
        var model = new TestViewModel;
        model.SourceColumns = GetSourceColumns();
        model.DestinationColumns = GetDestinationColumns();     
        return View(model);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult MapColumns(TestViewModel model)
    {
        if( Validate(model) )
        {
            // Do something with model.ColumnMappings
            RedirectToAction("Index");
        }
        else
        {
             // Here model.SourceColumns and model.DestinationColumns are empty
            return View(model);
        }
    }

}

The relevant section of MapColumns.aspx:

<%
int columnCount = 0;
foreach(string column in Model.targetColumns)
{%>
        <tr>
            <td> 
                <input type="hidden" name="ColumnMappings[<%= columnCount %>].Value" value="<%=column %>" />
                <%= Html.DropDownList("ColumnMappings[" + columnCount + "].Key", Model.DestinationColumns.AsSelectItemList())%>
            </td>            
        </tr>
    <%
    columnCount++;
}%>
A: 

You'll have to rebind your model if validation fails. In your else statement just add the, model.SourceColumns = GetSourceColumns(); and model.DestinationColumns = GetDestinationColumns(); before returning the view again.

Victor
Thanks for the reply. I was really wondering if there was a clever way I could avoid making a second call to GetSourceColumns() GetDistnationColumns(). As there doesn't appear to be I will just resort to repopulating these fields by calling the functions again, and look into improving the effeciency of the functions if this proves a problem later.
TonE
That's exactly what I've done; just work on improving the efficiency of these calls.
Victor