MVC3 - Insert using ViewModel - Object reference not set to an instance of an object
Asked Answered
H

3

14

I have got two models, seen below, and am trying to insert one of each to the database from one view. I have created a view model in an attempt to do this.

public class Blog
{
    public int BlogID { get; set; }
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }

    public virtual User User { get; set; }
    public virtual ICollection<BlogPost> Posts { get; set; }     
}

public class BlogPost
{
    public int PostID { get; set; }
    public string Body { get; set; }
    public DateTime CreatedOn { get; set; }

    public int UserID { get; set; }
    public virtual User User { get; set; }
}

public class BlogViewModel
{
    public Blog Blog { get; set; }
    public BlogPost BlogPost { get; set; }
}

Using the view model i am posting to the create controller:

[HttpPost]
    public ActionResult Create(BlogViewModel blog)
    {
        if (ModelState.IsValid)
        {
            User user = unit.UserRepository.GetUser();
            blog.Blog.User = user;
            blog.Blog.CreatedOn = DateTime.Now;

            unit.BlogRepository.Insert(blog.Blog);
            unit.BlogPostRepository.Insert(blog.BlogPost);
            unit.Save();

            return RedirectToAction("Index");  
        }

        return View(blog);
    }

This keep throwing the error

Object reference not set to an instance of an object.

on the line blog.Blog.User = user.

Any thoughts on what i'm doing wrong?

EDIT I checked the POST data and it was all there and correct but it was posting everything as Blog.Title = and BlogPost.Body = so the viewmodel in the controller wasn't receiving anything. If i change the controller actionresult to:

public ActionResult Create(Blog blog, BlogPost post)

Then it all works. So why doesn't data sent in the viewmodel format? I am using explicit view model based interaction between your views and controller

@model Test.Models.BlogViewModel
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Blog</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Blog.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Blog.Title)
            @Html.ValidationMessageFor(model => model.Blog.Title)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.BlogPost.Body)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.BlogPost.Body)
            @Html.ValidationMessageFor(model => model.BlogPost.Body)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
Hackberry answered 5/11, 2011 at 13:31 Comment(0)
E
35

Simply rename your action argument:

public ActionResult Create(BlogViewModel viewModel)

There is a conflict because your action argument is called blog and yet your view model (BlogViewModel) has a property called Blog. The problem is that the default model binder no longer knows what to do in such situation.

Oh and if you absolutely need to have your action argument called blog then you could also rename the Blog property on your view model.

Ecbatana answered 5/11, 2011 at 17:39 Comment(0)
A
4

I have ran in these kinds of situation before. This happens, when the data that you are sending from your view is not in a format, that MVC default model binding engine can understand or can map to your view model object. Try using "FireBug" and see as how the data is being passed via POST. And then see, if that data can be mapped to the definition of your view model.

One more thing, are you using jQuery to pass the data or you are using explicit view model based interaction between your views and controller ?

Abet answered 5/11, 2011 at 13:37 Comment(0)
S
0

@Michael Willmott

Although this topic is 6 years old but i find out it useful for a scenario I have dealt with recently.

In my MVC view, instead using a full path for identifiers, I used inline short cut variable with Razor and that caused the postback view model to server was null. That was because the "name" and "id" attributes for html elements were not rendered correctly as MVC binding mechanism expects:

The following is wrong declaration:

@{
   var b = Model.Blog; // short cut caused problem of postback model binding
}

<div class="editor-field">
            @Html.EditorFor(model => b.Title)
            @Html.ValidationMessageFor(model => b.Title)
        </div>

The following is correct declaration as full path for identifiers is needed:

<div class="editor-field">
            @Html.EditorFor(model => model.Blog.Title)
            @Html.ValidationMessageFor(model => model.Blog.Title)
        </div>
Schwarz answered 12/11, 2017 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.