using System.ComponentModel.DataAnnotations;
namespace DevAstuces.Models
{
public class Article
{
[Key]
public int Id { get; set; }
public virtual User Author { get; set; }
[Required]
public virtual Category Category { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Content { get; set; }
public enum ArticleStatus
{
Pending,
Rejected,
Validated
}
public ArticleStatus Status { get; set; }
}
}
Category.cs
using System.ComponentModel.DataAnnotations;
namespace DevAstuces.Models
{
public class Category
{
[Key]
public int Id { get; set; }
public byte[] Image { get; set; }
[Required]
public string Name { get; set; }
}
}
using System.Linq;
using System.Threading.Tasks;
using DevAstuces.Data;
using DevAstuces.Models;
using Microsoft.AspNetCore.Mvc;
namespace DevAstuces.Controllers
{
public class ArticleController : Controller
{
private readonly ArticleContext _articlecontext;
public ArticleController(ArticleContext articlecontext)
{
_articlecontext = articlecontext;
}
[HttpGet]
public IActionResult Publish()
{
ViewData["CategoryList"] = _articlecontext.Category.ToList();
return View();
}
[HttpPost]
public IActionResult Publish(Article article)
{
if(!ModelState.IsValid)
return View();
return RedirectToAction("Index","Home");
}
}
}
So, for the moment being, I get a NullReferenceException when submitting the form as a HttpPost request (no extra operations actually) which should just RedirectToAction as there is no logic inside the Publish method.
NullReferenceException: Object reference not set to an instance of an object.
But I do have two categories present in my DB and the generated HTML code is just here :
<form id="editor_pane" method="POST">
<input type="list" list="Category" placeholder="Catégorie" name="Category">
<datalist id="Category">
<option value="NodeJS"></option>
<option value="csharp"></option>
</datalist>
<input type="text" placeholder="Saisissez le titre de votre astuce/article ici" name="Title">
<input type="text" placeholder="Description" name="Description">
</form>
@foreach(var category in (List<Category>)ViewData["CategoryList"])
{
<option value="@category.Name"></option>
}
System.NullReferenceException: Object reference not set to an instance of an object.
at AspNetCore.Views_Article_Publish.<ExecuteAsync>b__16_4() in C:\Users\Théo\Code\DevAstuces\Views\Article\Publish.cshtml:line 17
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.GetChildContentAsync(Boolean useCachedResult, HtmlEncoder encoder)
at Microsoft.AspNetCore.Mvc.TagHelpers.RenderAtEndOfFormTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, Int32 i, Int32 count)
at AspNetCore.Views_Article_Publish.<ExecuteAsync>b__16_1()
at Microsoft.AspNetCore.Mvc.Razor.RazorPage.RenderSectionAsyncCore(String sectionName, Boolean required)
at Microsoft.AspNetCore.Mvc.Razor.RazorPage.RenderSection(String name, Boolean required)
at AspNetCore.Views_Shared__Layout.<ExecuteAsync>b__13_1() in C:\Users\Théo\Code\DevAstuces\Views\Shared\_Layout.cshtml:line 16
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
at AspNetCore.Views_Shared__Layout.ExecuteAsync()
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable`1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
but as you can see the HTML code is well generated and the data from the DB is perfectly fine
It sounds like you are telling us the code you shared does not cause the null exception. Can you share the code that does cause the null exception. Typically, the line of code is displayed in the developer error page in red.
I suspect there is a model validation error because you are missing one of the [Required] fields in the HTML Form. There's also the Category type which will always be null. Anyway, the exception happens because the options do not exist in the model posted
to Publish Action and you are not passing the mode or option to the View.
Simply use the Visual Studio debugger to view what your code is doing. Most likely you made a few assumptions like the option persist between requests but you did not verify your assumption is correct.
Re your problem -- set breakpoints in each method of your controller to see which method is invoked on POST. It's possible that your code is not set up correctly and it tries to render "Publish" page on post response, and whatever controller's method is
doing that rendering is not supplying the ViewData.
I found the issue, it is due to the ModelState validation and the fact that I pass an Article object to the view :
[HttpPost]
public IActionResult Publish(Article article)
{
if(!ModelState.IsValid)
return View(article); // Error occurs here
return RedirectToAction("Index","Home");
}
Now that I use a "View Model" approach, I have a more detailed error output :
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'DevAstuces.Models.Article', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.List`1[DevAstuces.Models.Category]'.
So, according to this error I should also define a @model directive into the CSHTML file but I can only give one ?
@model List<DevAstuces.Models.Category>
@model DevAstuces.Models.Article // The "model" directive may only occur once per document
@{
Layout = "_Layout";
ViewData["Title"] = "Publier";
}
@section page_styles{
<link href="~/css/Article/publish.css" type="text/css" rel="stylesheet">
}
@section page_content{
<h1>Publier</h1>
<form id="editor_pane" method="POST">
<input type="list" list="Category" placeholder="Catégorie" name="Category">
<datalist id="Category">
@foreach(var category in Model)
{
<option value="@category.Name"></option>
}
</datalist>
<input type="text" placeholder="Saisissez le titre de votre astuce/article ici" name="Title">
<input type="text" placeholder="Description" name="Description">
<div id="editor_controls">
<button type="button" onclick="previewArticle()">Prévisualiser</button>
<input value="Valider" type="submit">
</div>
</form>
}
@section page_scripts{
<script src="~/js/Article/editor.js"></script>
}
So, according to this error I should also define a @model directive into the CSHTML file but I can only give one ?
A view model (C# class) can contain one or many models. This is generally referred to a complex type or in MVC a View Model when the data is used to generate the UI (View).
I recommend going through the Getting Started tutorials on this site as they cover these basic MVC programming concepts.
As the error message says, you can only have one model directive. If your View needs to make use of both a single Category (selected for POST) as well as the list of all categories, then you need to create a separate model class that has those fields, and
pass an instance of that class.
Also, in the following code you need to pass an instance of the model as well:
valenciano8
return RedirectToAction("Index","Home", model); // add "model" to list of params
Alternatively you can look at post-and-redirect pattern, where a different controller endpoint & a different view is used to display a successful post result.
Thanks a lot, the ViewModel approach solved the issue and is indeed advised for compile time type checking.
Here is my ViewModel composed of a List of Category and an Article :
using System.Collections.Generic;
using DevAstuces.Models;
namespace DevAstuces.ViewModels
{
public class ArticleViewModel
{
public List<Category> Category { get; set; }
public Article Article { get; set; }
}
}
Here is my new ArticleController code for the Publish Method :
[HttpGet]
public IActionResult Publish()
{
var ArticleViewModel = new ArticleViewModel();
ArticleViewModel.Category = _articlecontext.Category.ToList();
return View(ArticleViewModel);
}
[HttpPost]
public IActionResult Publish(ArticleViewModel ArticleViewModel)
{
ArticleViewModel.Category = _articlecontext.Category.ToList();
if(!ModelState.IsValid)
return View(ArticleViewModel);
return RedirectToAction("Index","Home");
}
NB : the documentation should have a "more beginner friendly" tutorial for MVMC and also should explain how to create a ViewModel with multiple models because I had to search on the web for that..
Member
10 Points
73 Posts
[MVC] Strange NullReferenceException
Feb 16, 2021 10:43 AM|valenciano8|LINK
Hi everyone,
I'm facing a strange NullReferenceException.
Indeed I've built a simple Publish Article form.
An article is :
Category.cs
Publish.cshtml
ArticleController.cs
So, for the moment being, I get a NullReferenceException when submitting the form as a HttpPost request (no extra operations actually) which should just RedirectToAction as there is no logic inside the Publish method.
But I do have two categories present in my DB and the generated HTML code is just here :
Thanks in advance for your help
All-Star
52971 Points
23574 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 12:22 PM|mgebhard|LINK
The code you've shared has a lot of potential errors.
The null exception always shows the line and item that's null. It is a lot easier if you share what is null rather than making us guess.
Member
10 Points
73 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 03:01 PM|valenciano8|LINK
Hi @mgebhard,
Here is the full Error Output :
Is it what you meant ? :(
All-Star
58144 Points
15641 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 05:01 PM|bruce (sqlwork.com)|LINK
the error means
ViewData["CategoryList"]
is null. so your action is failing to set it to a valid value.
Member
10 Points
73 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 05:05 PM|valenciano8|LINK
Hi @bruce,
Thank you for your answer.
Yes, that's what I understand but as you can see the HTML code is well generated and the data from the DB is perfectly fine :
All-Star
52971 Points
23574 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 09:47 PM|mgebhard|LINK
It sounds like you are telling us the code you shared does not cause the null exception. Can you share the code that does cause the null exception. Typically, the line of code is displayed in the developer error page in red.
Perhaps you can debug the code?
https://docs.microsoft.com/en-us/visualstudio/debugger/debugger-feature-tour?view=vs-2019
Member
10 Points
73 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 09:52 PM|valenciano8|LINK
It's this line :
But I don't understand how it can produce a NullReferenceException as the HTML Code hereafter shows that it retreived entities through CategoryList :
All-Star
52971 Points
23574 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 09:58 PM|mgebhard|LINK
I suspect there is a model validation error because you are missing one of the [Required] fields in the HTML Form. There's also the Category type which will always be null. Anyway, the exception happens because the options do not exist in the model posted to Publish Action and you are not passing the mode or option to the View.
Simply use the Visual Studio debugger to view what your code is doing. Most likely you made a few assumptions like the option persist between requests but you did not verify your assumption is correct.
Member
100 Points
31 Posts
Re: [MVC] Strange NullReferenceException
Feb 16, 2021 10:27 PM|artem_s|LINK
Re your problem -- set breakpoints in each method of your controller to see which method is invoked on POST. It's possible that your code is not set up correctly and it tries to render "Publish" page on post response, and whatever controller's method is doing that rendering is not supplying the ViewData.
Also,
Time and again I urge developers to avoid using ViewData and similar ways of data transfer and use View Models instead.
Just try passing your list as a model to the view instead:
...and in your Publish.cshtml declare the model type at the top:
You will avoid most of the run time errors this way and will have compile time type-checking out of the box.
Member
10 Points
73 Posts
Re: [MVC] Strange NullReferenceException
Feb 18, 2021 02:01 PM|valenciano8|LINK
Hi,
I found the issue, it is due to the ModelState validation and the fact that I pass an Article object to the view :
Now that I use a "View Model" approach, I have a more detailed error output :
So, according to this error I should also define a @model directive into the CSHTML file but I can only give one ?
How can I proceed ?
All-Star
52971 Points
23574 Posts
Re: [MVC] Strange NullReferenceException
Feb 18, 2021 02:20 PM|mgebhard|LINK
A view model (C# class) can contain one or many models. This is generally referred to a complex type or in MVC a View Model when the data is used to generate the UI (View).
I recommend going through the Getting Started tutorials on this site as they cover these basic MVC programming concepts.
https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-5.0&tabs=visual-studio
https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/?view=aspnetcore-5.0
Member
100 Points
31 Posts
Re: [MVC] Strange NullReferenceException
Feb 18, 2021 08:32 PM|artem_s|LINK
As the error message says, you can only have one model directive. If your View needs to make use of both a single Category (selected for POST) as well as the list of all categories, then you need to create a separate model class that has those fields, and pass an instance of that class.
Also, in the following code you need to pass an instance of the model as well:
Alternatively you can look at post-and-redirect pattern, where a different controller endpoint & a different view is used to display a successful post result.
Member
10 Points
73 Posts
Re: [MVC] Strange NullReferenceException
Feb 19, 2021 08:09 AM|valenciano8|LINK
Hi,
Thanks a lot, the ViewModel approach solved the issue and is indeed advised for compile time type checking.
Here is my ViewModel composed of a List of Category and an Article :
Here is my new ArticleController code for the Publish Method :
NB : the documentation should have a "more beginner friendly" tutorial for MVMC and also should explain how to create a ViewModel with multiple models because I had to search on the web for that..