Null Reference Exception while using an EFCore List ?

Valenciano8 116 Reputation points
2021-07-24T21:21:15.723+00:00

Hi everyone,

I'm facing an issue of "Null Reference Exception" when I submit an empty Form whereas I did a ModelState verification. (see my HomeController and Index page)

The exact error occurs when the breakpoints hits line 40 inside HomeController and I get :

NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_Home_Index.<ExecuteAsync>b__14_0() in Index.cshtml
+
@foreach (var book in @默 .BookList)

Indeed here is my code :

IndexViewModel.cs :

using System.Collections.Generic;  
using Blog.Models;  
  
namespace Blog.ViewModels.Home  
{  
    public class IndexViewModel  
    {  
        public BookViewModel BookViewModel { get; set; }  
        public List<Book> BookList { get; set; }  
    }  
}  

BookViewModel.cs :

using System.ComponentModel.DataAnnotations;  
  
namespace Blog.ViewModels.Home  
{  
    public class BookViewModel  
    {  
        [Required(ErrorMessage = "Please specify a name")]  
        [Display(Name = "Name : ")]  
        public string Name { get; set; }  
  
        [Required(ErrorMessage = "Please specify a price")]  
        [Display(Name = "Price : ")]  
        public int Price { get; set; }  
    }  
}  

Index.cshtml :

@model Blog.ViewModels.Home.IndexViewModel  
@{  
    ViewData["Title"] = "Blog";  
    Layout = "_Layout";  
}  
  
@section page_content{  
    <p>Hello World form Blog !</p>  
  
    <form asp-controller="Home" asp-action="Index" method="post">  
        <label asp-for="@Model.BookViewModel.Name"></label>  
        <input asp-for="@Model.BookViewModel.Name">  
        <span asp-validation-for="@Model.BookViewModel.Name"></span>  
  
        <label asp-for="@Model.BookViewModel.Price"></label>  
        <input asp-for="@Model.BookViewModel.Price">  
        <span asp-validation-for="@Model.BookViewModel.Price"></span>  
  
        <input type="submit" value="Continuer">  
    </form>  
  
    <table>  
        <thead>  
            <th>  
                <td>Name</td>  
                <td>Price</td>  
            </th>  
        </thead>  
        <tbody>  
            @foreach (var book in @Model.BookList)  
            {  
                <tr>  
                    <td>@book.Name</td>  
                    <td>@book.Price</td>  
                </tr>     
            }  
        </tbody>  
    </table>  
}  

HomeController.cs

using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
using Blog.Data;  
using Blog.Models;  
using Blog.ViewModels.Home;  
using Microsoft.AspNetCore.Mvc;  
  
namespace Blog.Controllers  
{  
    public class HomeController : Controller  
    {  
        private readonly BookDbContext _bookDbContext;  
        public HomeController(BookDbContext bookDbContext)  
        {  
            _bookDbContext = bookDbContext;  
        }  
  
        public IActionResult Index()  
        {  
            var indexViewModel = new IndexViewModel();  
  
            var bookList = _bookDbContext.Book.ToList();  
  
            if(bookList != null)  
            {  
                indexViewModel.BookList = bookList;  
                System.Console.WriteLine("BookList was not null => " + indexViewModel.BookList.ToString());  
            }  
              
            return View(indexViewModel);  
        }  
  
        [HttpPost]  
        [ValidateAntiForgeryToken]  
        public async Task<IActionResult> Index(IndexViewModel indexViewModel)  
        {  
            if(!ModelState.IsValid)  
            {  
                // Null Reference Exception is triggered below  
                System.Console.WriteLine("Book CreationForm was not valid");  
                return View(indexViewModel);  
            }  
  
            var new_book = new Book{  
                Name = indexViewModel.BookViewModel.Name,  
                Price = indexViewModel.BookViewModel.Price   
            };  
  
            await _bookDbContext.AddAsync(new_book);  
            await _bookDbContext.SaveChangesAsync();  
  
            return RedirectToAction("Index", "Home");  
        }  
    }  
}  

Thanks in advance for your help

Developer technologies ASP.NET ASP.NET Core
0 comments No comments
{count} votes

Accepted answer
  1. Bruce Barker 801 Reputation points
    2021-07-24T21:31:14.273+00:00

    The view expects Model.BookList to not be null. The list will not be included in the postback data, so it is null. The postback code should recreate the list before calling the view.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Valenciano8 116 Reputation points
    2021-07-24T23:03:06.827+00:00

    Hi @Bruce Barker , you were right, thank you !

    Here is my updated code which now works :)

    using System.Collections.Generic;  
    using System.Linq;  
    using System.Threading.Tasks;  
    using Blog.Data;  
    using Blog.Models;  
    using Blog.ViewModels.Home;  
    using Microsoft.AspNetCore.Mvc;  
      
    namespace Blog.Controllers  
    {  
        public class HomeController : Controller  
        {  
            private readonly BookDbContext _bookDbContext;  
            public HomeController(BookDbContext bookDbContext)  
            {  
                _bookDbContext = bookDbContext;  
            }  
      
            public IActionResult Index()  
            {  
                var indexViewModel = new IndexViewModel();  
      
                var bookList = _bookDbContext.Book.ToList();  
      
                if(bookList != null)  
                {  
                    indexViewModel.BookList = bookList;  
                    System.Console.WriteLine("BookList was not null => " + indexViewModel.BookList.ToString());  
                }  
                  
                return View(indexViewModel);  
            }  
      
            [HttpPost]  
            [ValidateAntiForgeryToken]  
            public async Task<IActionResult> Index(IndexViewModel indexViewModel)  
            {  
                if(!ModelState.IsValid)  
                {  
                    indexViewModel.BookList = _bookDbContext.Book.ToList();  
                    return View(indexViewModel);  
                }  
      
                var new_book = new Book{  
                    Name = indexViewModel.BookViewModel.Name,  
                    Price = indexViewModel.BookViewModel.Price   
                };  
      
                await _bookDbContext.AddAsync(new_book);  
                await _bookDbContext.SaveChangesAsync();  
      
                return RedirectToAction("Index", "Home");  
            }  
        }  
    }  
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.