0

Currently I have a ViewModel which is comprised of 2 lists of models. Displaying contents using the ViewModel is fine, however when I try to post I get a null reference exception.

public class DashboardViewModel
{
    public IList<DashboardModel> dashboard { get; set; }
    public IList<WidgetModel> widgets { get; set; }
}

Here is the form on the view

 @using (Html.BeginForm("AddDashboard", "Dashboard", FormMethod.Post))
            {
                @Html.AntiForgeryToken()

                <div class="form-horizontal">
                    <h4>DashboardModel</h4>
                    <hr />
                    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                    <div class="form-group">
                        @Html.LabelFor(model => model.dashboard.Last().DashName, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.dashboard.Last().DashName, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.dashboard.Last().DashName, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                            <button type="submit" value="AddDashboard" class="btn btn-primary">Save changes</button>
                        </div>
                    </div>
                </div>
            }

and here is my action

 [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult AddDashboard([Bind(Include = "DashID,DashName,CreatedBy,CreatedDate")] DashboardViewModel dashboardVM)
    {
        if (ModelState.IsValid)
        {
            DashboardModel newDashboard = dashboardVM.dashboard.Last();
            newDashboard.CreatedBy = User.Identity.GetUserId();
            newDashboard.CreatedDate = DateTime.Now;

            db.dashboards.Add(newDashboard);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(dashboardVM);
    }

The null reference happens in the AddDashboard action I have set a breakpoint and realised that dashboardVM is null, the dashboard property is null

Johnathon64
  • 1,280
  • 1
  • 20
  • 45
  • 1
    Your not generating controls that have no relationship to your model. Property `dashboard` is a collection, so you need to generate the controls in a `for` loop (or use a custom `EditorTemplate` for type of `DashboardModel`) –  May 20 '15 at 10:44
  • 1
    You are not sending a list back. Change the post action to accept a DashboardModel. – Brendan Green May 20 '15 at 10:46
  • `@Html.EditorFor(model => model.dashboard.Last().DashName, ...` won't work as `.Last()` is an `IEnumerable` and is therefore readonly. – Tom Chantler May 20 '15 at 10:47
  • And look at the html your generating. In order to bind your control need to be `` and the you need to remove that `[Bind]` attribute –  May 20 '15 at 10:50
  • @BrendanGreen That solved my problem thanks, do you want to put it as an answer so I can give you a green tick? – Johnathon64 May 20 '15 at 10:55
  • possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Daniel Kelley May 20 '15 at 10:55

2 Answers2

2

Your [Bind] attribute is causing the dashboard (and widgets) property of your view-model to remain null because you don't include dashboard in the Include list.

Try to remove the [Bind] from your action parameter and place it on the DashboardModel itself:

[Bind(Include = "DashID,DashName,CreatedBy,CreatedDate")]
public class DashboardModel
{
    // ...
}

See MSDN

haim770
  • 48,394
  • 7
  • 105
  • 133
  • I have followed your instructions however this didn't seem to solve my problem – Johnathon64 May 20 '15 at 10:49
  • It's seems like this is only part of the problem, the other problem is related to your usage of `EditorFor()`. Will look into this later – haim770 May 20 '15 at 10:51
0

Your HttpPost action is receiving a DashboardViewModel, which internally contains, among other properties, a collection of DashboardModel.

However, you are not passing in a collection of anything, but rather a single DashboardModel.

Update your action to accept a DashboardModel instead:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddDashboard([Bind(Include = "DashID,DashName,CreatedBy,CreatedDate")] DashboardModel dashboardVM)
{
    ...
}

Note: [Bind] properties may need to be adjusted; you have not provided a definition of the DashboardModel class.

Brendan Green
  • 11,676
  • 5
  • 44
  • 76