Home > Back-end >  ASP.NET Core MVC modifying entity causes NullReferenceException
ASP.NET Core MVC modifying entity causes NullReferenceException

Time:09-21

I am facing a problem most of you (including me) would solve immeditately by placing a hidden input to forms, but this time I have tried almost everything. I would like to modify an InputForm entity by adding a SolarPanelType entity. Because of the loads of another options, I use viewmodels embedded as you can see

public class InputFormViewModel
    {
        public InputForm InputForm { get; set; }
        public IEnumerable<TetoTipus> TetoTipusEnumerable { get; set; }
        public IEnumerable<TetoFedes> TetoFedesEnumerable { get; set; }
        public IEnumerable<TetoDoles> TetoDolesEnumerable { get; set; }
        public IEnumerable<NapelemElhelyezes> NapelemElhelyezesEnumerable { get; set; }
        public IEnumerable<NapelemTipus> NapelemTipusEnumerable { get; set; }
    }
public class ModifyInputFormViewModel
    {
        public InputFormViewModel InputFormViewModel;
        public SelectList SolarPanelTypesList { get; set; }
    }

And I initialize them in my controller like this

public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            ModifyInputFormViewModel modifyInputFormViewModel = new()
            {
                InputFormViewModel = new InputFormViewModel
                {
                    InputForm = await _inputFormService.FindInputFormAsync(id),
                    TetoTipusEnumerable = await _inputFormService.GetTetoTipusokAsync(),
                    TetoFedesEnumerable = await _inputFormService.GetTetoFedesekAsync(),
                    TetoDolesEnumerable = await _inputFormService.GetTetoDolesekAsync(),
                    NapelemElhelyezesEnumerable = await _inputFormService.GetNapelemElhelyezesekAsync(),
                    NapelemTipusEnumerable = await _inputFormService.GetNapelemTipusokAsync()
                },
                SolarPanelTypesList = new SelectList(await _solarPanelTypeService.GetSolarPanelTypesAsync(), "ID", "DisplayString")
            };
            if (modifyInputFormViewModel.InputFormViewModel.InputForm == null)
            {
                return NotFound();
            }
            return View(modifyInputFormViewModel);
        }

And the POST method

[HttpPost, ValidateAntiForgeryToken, Authorize]
        public async Task<IActionResult> Edit(int id, ModifyInputFormViewModel modifyInputFormViewModel)
        {
            if (id != modifyInputFormViewModel.InputFormViewModel.InputForm.ID)
            {
                return NotFound();
            }
            if (ModelState.IsValid)
            {
                await _inputFormService.ModifyInputFormAsync(modifyInputFormViewModel.InputFormViewModel.InputForm);
                return RedirectToAction(nameof(Index));
            }
            return View(modifyInputFormViewModel);
        }

Finally, here is the crucial part of Edit view

<form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="InputFormViewModel.InputForm.ID" />
            <div class="form-group">
                <label asp-for="InputFormViewModel.InputForm.SolarPanelType" class="control-label"></label>
                <select asp-for="InputFormViewModel.InputForm.SolarPanelTypeID" asp-items="@Model.SolarPanelTypesList" class="form-control"></select>
            </div>
            <div class="form-group">
                <label asp-for="InputFormViewModel.InputForm.MonthlyElectricityBill" class="control-label"></label>
                <input asp-for="InputFormViewModel.InputForm.MonthlyElectricityBill" class="form-control" />
                <span asp-validation-for="InputFormViewModel.InputForm.MonthlyElectricityBill" class="text-danger"></span>
            </div>

            <section id="TetoTipusSection">
                <h5>@Html.DisplayNameFor(model => model.InputFormViewModel.InputForm.TetoTipus)</h5>
                <p>
                    @foreach (TetoTipus tetoTipus in Model.InputFormViewModel.TetoTipusEnumerable)
                    {
                        <label>
                            <input type="radio" asp-for="InputFormViewModel.InputForm.TetoTipusID" value="@tetoTipus.ID" /> @tetoTipus.Name
                        </label>
                        <br />
                    }
                </p>
                <hr />
            </section>

            [...]
        </form>

Last important information is that the view renders EXACTLY what I want, the hidden input contains InputForm.ID correctly, but then the post method receives NULL value.

CodePudding user response:

Update you code like below:-

<form asp-action="Edit" method="post" enctype="multipart/form-data">

and your controller:-

[HttpPost]
public async Task<IActionResult> Edit(int? ID){...}

Hope it will resolve your issue.

CodePudding user response:

fix the view, since you use AntiForgeryToken add it to form

<form asp-action="Edit" method="post">
 @Html.AntiForgeryToken()

and action input parameter should be the same as a model, remove id

 public async Task<IActionResult> Edit( ModifyInputFormViewModel modifyInputFormViewModel)
{
 var id= modifyInputFormViewModel.InputFormViewModel.InputForm.ID;
.......
  • Related