Home > Back-end >  ASP.NET Core 5 MVC: ArgumentNullException: Value cannot be null. (Parameter 'items')
ASP.NET Core 5 MVC: ArgumentNullException: Value cannot be null. (Parameter 'items')

Time:11-04

I have this list in the GET method for a create page:

List<string> users = (from c in _context.NR_Users select c.Name).ToList();
users.Insert(0, "Select");
ViewBag.users = users;

It is displayed like this:

<div class="form-group col-md-4">
    <label class="control-label">Prepared By</label>
    <select asp-for="Prepared_By" name="Prepared_By" class="form-control" asp-items="@(new SelectList(ViewBag.users))"></select>
    <span asp-validation-for="Prepared_By" class="text-danger"></span>
</div>

In the model Prepared_By is a string.

On the create page when I hit submit I get the following error:

ArgumentNullException: Value cannot be null. (Parameter 'items')

pointing to

<select asp-for="Prepared_By" name="Prepared_By" class="form-control" asp-items="@(new SelectList(ViewBag.users))"></select>

There are a couple things I find really interesting about this issue. First of all, in the POST method for the create page if I print the value of Prepared_By it always prints the correct name:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,State_Project_Number,Federal_Project_Number,Name,Route_Number,County,Work_Type,Coordinates,Project_Description,Federal_Aid,Minimal_Project_Verification,CE_Category,Amms,Activities_Agreement,Arch_RE,Hist_RE,Arch_RE_Date,Hist_RE_Date,Through_Lanes,Close_Road,ROW_Acquisition,Access_Control,Fifty_Year_Structure,Agency_Coordination,IPAC_Screening_Zone,Section_404_Permit,Ground_Disturbance,Waterway,Special_Use_Permit,Floodplain,Prepared_By,Approved_By,Adduser,Date_Added")] TypeOne typeOne, bool Assessment)
{
    System.Diagnostics.Debug.WriteLine("Prepared by: "   typeOne.Prepared_By);

    if (ModelState.IsValid)
    {
        typeOne.Adduser = User.Identity.Name;
        typeOne.Date_Added = DateTime.Today;

        System.Diagnostics.Debug.WriteLine("Prepared by again: "   typeOne.Prepared_By);

        _context.Add(typeOne);
        await _context.SaveChangesAsync();
    }
}

However when I try to print it a second time inside the if(ModelState.IsValid) it does not work.

What else is interesting is that I use this exact same list in a different create page and it works just fine:

<div class="form-group col-md-3">
    <label class="control-label">DSN PM</label>
    <select asp-for="DSN_PM" name="DSN_PM" class="form-control" asp-items="@(new SelectList(ViewBag.users))"></select>
    <span asp-validation-for="DSN_PM" class="text-danger"></span>
</div>
public async Task<IActionResult> Create([Bind("ID,State_Project_Number,Federal_Project_Number,Project_Name,County,Memo_Date,From,Authorization,DSN_PM,History,History_PM,Review_Exempt_H,SHPO_Approval_H,Archaeology,Archaeology_PM,Review_Exempt_A,SHPO_Approval_A,ESA_Key,Crayfish,Crayfish_Habitat_Assessment,NLEB_4D,USFWS,USFWS_Type,Mussel_Habitat,Mussel_Stream,Within_Airport,ToPo_Quad_Name,Bat_Habitat,Bars,Coordinates,Natural_Resources_Notes,Adduser,Date_Added,Crayfish_Notes,Mussel_Notes")] Project_Screen project_Screen)
{
    if (ModelState.IsValid)
    {
        project_Screen.Adduser = User.Identity.Name;
        project_Screen.Date_Added = DateTime.Today;

        _context.Add(project_Screen);

        await _context.SaveChangesAsync();

        return RedirectToAction(nameof(Index));
    }

    return View(project_Screen);
}

In the second example I create the list in the exact same way in the GET method and I have never had this issue. What could be the problem?

EDIT: Update from question

Controller:

 [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("ID,State_Project_Number,Federal_Project_Number,Name,Route_Number,County,Work_Type,Coordinates,Project_Description,Federal_Aid,Minimal_Project_Verification,CE_Category,Amms,Activities_Agreement,Arch_RE,Hist_RE,Arch_RE_Date,Hist_RE_Date,Through_Lanes,Close_Road,ROW_Acquisition,Access_Control,Fifty_Year_Structure,Agency_Coordination,IPAC_Screening_Zone,Section_404_Permit,Ground_Disturbance,Waterway,Special_Use_Permit,Floodplain,Prepared_By,Approved_By,Adduser,Date_Added")] TypeOne typeOne, bool Assessment)
        {
            System.Diagnostics.Debug.WriteLine("Prepared by: "   typeOne.Prepared_By);
            if (ModelState.IsValid)
            {
                typeOne.Adduser = User.Identity.Name;
                typeOne.Date_Added = DateTime.Today;
                System.Diagnostics.Debug.WriteLine("Prepared by again: "   typeOne.Prepared_By);
                _context.Add(typeOne);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            //set the data for ViewBag.users..
            List<string> users = (from c in _context.NR_Users select c.Name).ToList();
            users.Insert(0, "Select");
            ViewBag.users = users;
            return View(typeOne);
        }

View:

<div class="form-group col-md-4">
                    <label class="control-label">Prepared By</label>
                    <select asp-for="Prepared_By" name="Prepared_By" class="form-control" asp-items="@(new SelectList(ViewBag.users,"Id","Name"))"></select>
                    <span asp-validation-for="Prepared_By" class="text-danger"></span>
                </div>

There are a couple of problems here. First of all, the problem persists and nothing has changed. I'm not sure if the code for the view is correct at all, but it is giving me a Object reference not set to an instance of an object. error but I don't really know what it's pointing to. I also don't know why you added ID because I don't use that anywhere and I don't need to.

CodePudding user response:

Can you please check the ASP.NET <form /> element? It should look like this:

<form asp-controller="MyController" asp-action="MyAction" method="post">
    <!-- Your controls and etc -->
</form>

CodePudding user response:

First of all, in the POST method for the create page if I print the value of Prepared_By it always prints the correct name

Of course it will print the correct value, because you post the data to backend successfully. But you need to know the dropdown populated data is not store by Prepared_By. It stores value by using asp-items="@(new SelectList(ViewBag.users))". You do not set the ViewBag.users in your post method, that is why you makes ArgumentNullException error when you post back.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,State_Project_Number,Federal_Project_Number,Name,Route_Number,County,Work_Type,Coordinates,Project_Description,Federal_Aid,Minimal_Project_Verification,CE_Category,Amms,Activities_Agreement,Arch_RE,Hist_RE,Arch_RE_Date,Hist_RE_Date,Through_Lanes,Close_Road,ROW_Acquisition,Access_Control,Fifty_Year_Structure,Agency_Coordination,IPAC_Screening_Zone,Section_404_Permit,Ground_Disturbance,Waterway,Special_Use_Permit,Floodplain,Prepared_By,Approved_By,Adduser,Date_Added")] TypeOne typeOne, bool Assessment)
{
    System.Diagnostics.Debug.WriteLine("Prepared by: "   typeOne.Prepared_By);

    if (ModelState.IsValid)
    {
        typeOne.Adduser = User.Identity.Name;
        typeOne.Date_Added = DateTime.Today;

        System.Diagnostics.Debug.WriteLine("Prepared by again: "   typeOne.Prepared_By);

        _context.Add(typeOne);
        await _context.SaveChangesAsync();
    }
    //set the data for ViewBag.users..
    List<string> users = (from c in _context.NR_Users select c.Name).ToList();
    users.Insert(0, "Select");
    ViewBag.users = users;
    //return View("ViewName", typeOne);
    //if you return Create.cshtml,  no need specify the view name
    return View(typeOne);
}

As for your second way, be sure debug your code and to see when it goes. It is impossible if you do not set value for ViewBag.users when you populate the dropdown. Be carefull if any difference.

Here is a whole simple working demo:

Model:

public class Test
{
    public string Id{ get; set; }
    public string Name { get; set; }
}

public class TestModel
{
    public string Prepared_By { get; set; }
}

View(Create.cshtml):

Besides, you need use public SelectList(IEnumerable items, string dataValueField, string dataTextField); which will display the correct value and text for dropdown.

model TestModel

<form method="post">
    <select asp-for="Prepared_By" name="Prepared_By" class="form-control" 
             asp-items="@(new SelectList(ViewBag.users,"Id","Name"))"></select>
    <input type="submit" value="Post" />
</form>

Controller:

[HttpGet]        
public IActionResult Create()
{

    var data = new List<User>()
    {
        new User(){ Id="1",Name= "aa" },
        new User(){ Id="2",Name= "bb" },
        new User(){ Id="3",Name= "cc" }               
    };
    ViewBag.users = data;
    return View();
}

public IActionResult Index(SuperModel model)
{
    ViewBag.users  = new List<Test>()
    {
        new Test(){ MenuCategoryId="1",Content= "aa" },
        new Test(){ MenuCategoryId="2",Content= "bb" },
        new Test(){ MenuCategoryId="3",Content= "cc" }
    };
    return View(model);
}
  • Related