question

Valenciano8-8704 avatar image
0 Votes"
Valenciano8-8704 asked Valenciano8-8704 edited

Null Reference Exception while using an EFCore List ?

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 @Model.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

dotnet-aspnet-core-mvc
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

BruceBarker-8516 avatar image
0 Votes"
BruceBarker-8516 answered

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.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Valenciano8-8704 avatar image
0 Votes"
Valenciano8-8704 answered Valenciano8-8704 edited

Hi @BruceBarker-8516, 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");
         }
     }
 }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.