RuntimeBinderException: Cannot perform runtime binding on a null reference

Viewed 1852

I'm making a create item page, and in this create item page there is a popup modal table where we can choose the type of UoM that we want. And normally when this form is submitted with all of the fields filled in, it saved the values into the database. But when the form is submitted with one or some or all of the fields not filled in, it supposed to give some error message that the fields are required. But it didn't and it shows this error.

enter image description here

These are my code

ItemController

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Threading.Tasks;
using CRMandOMS.Models;
using CRMandOMS.ViewModels;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace CRMandOMS.Controllers
{
    public class ItemController : Controller
    {
        private readonly IItemRepository _itemRepository;

        private readonly IUoMRepository _uoMRepository;

        public ItemController(IItemRepository itemRepository, IUoMRepository uoMRepository)
        {
            _itemRepository = itemRepository;
            _uoMRepository = uoMRepository;
        }

        // GET: /<controller>/
        public ViewResult Index()
        {
            var model = _itemRepository.GetAll();

            return View(model);
        }

        public ViewResult Details(Guid? id)
        {
            Item item = _itemRepository.GetById(id.Value);

            return View(item);
        }

        [HttpGet]
        public ViewResult Create()
        {
            ItemCreateViewModel itemCreateViewModel = new ItemCreateViewModel()
            {
                UoMs = _uoMRepository.GetAll()
            };

            return View(itemCreateViewModel);
        }

        [HttpPost]
        public IActionResult Create(ItemCreateViewModel model)
        {
            if (ModelState.IsValid)
            {
                Item newItem = new Item
                {
                    Name = model.Name,
                    Price = model.Price,
                    UoMId = model.UoMId
                };

                _itemRepository.Insert(newItem);

                return RedirectToAction("Details", new { id = newItem.Id });
            }

            return View();
        }
    }
}

Create

@model CRMandOMS.ViewModels.ItemCreateViewModel

@{
    ViewData["Title"] = "Item Create";
}

<h2>Item Create</h2>

<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
        <li class="breadcrumb-item"><a asp-controller="Item" asp-action="Index">Item</a></li>
        <li class="breadcrumb-item active" aria-current="page">Create</li>
    </ol>
</nav>

<form enctype="multipart/form-data" asp-controller="Item" asp-action="Create" method="post" class="mt-3">

    <div class="form-group row">
        <label asp-for="Name" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Name" class="form-control" placeholder="Name" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
    </div>

    <div class="form-group row">
        <label asp-for="Price" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Price" class="form-control" placeholder="Price" />
            <span asp-validation-for="Price" class="text-danger"></span>
        </div>
    </div>

    <div class="form-group row">
        <label asp-for="UoMId" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="UoMId" id="uomid" class="form-control" hidden />
            <div class="input-group mb-3">
                <input id="uomname" type="text" class="form-control" placeholder="UoM" aria-label="UoM" aria-describedby="button-uom" disabled>
                <div class="input-group-append">
                    <button class="btn btn-outline-success" type="button" id="button-uom" data-toggle="modal" data-target="#uoMLookupTableModal">Select UoM</button>
                </div>
            </div>
            <span asp-validation-for="UoMId" class="text-danger"></span>
        </div>
    </div>

    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group row">
        <div class="col-sm-2"></div>
        <div class="col-sm-10">
            <a asp-controller="Item" asp-action="Index" class="btn btn-light">Back</a>
            <button type="submit" class="btn btn-success">Create</button>
        </div>
    </div>
</form>

@{
    await Html.RenderPartialAsync("_UoMLookup");
}

@section scripts {
    <script>
        $(document).ready(function () {
            var uoMTable = $("#uoMTable").DataTable({
                "columnDefs": [
                    {
                        "targets": [0],
                        "visible": false
                    }
                ],
                "order": [[1, "asc"]]
            });

            $('#uoMTable tbody').on('click', 'tr', function () {
                if ($(this).hasClass('table-success')) {
                    $(this).removeClass('table-success');
                }
                else {
                    uoMTable.$('tr.table-success').removeClass('table-success');
                    $(this).addClass('table-success');
                }
            });

            $("#getUoM").click(function () {
                var uomdata = uoMTable.row('.table-success').data();

                //alert(uomdata[0]);
                $('#uomid').val(uomdata[0]);

                //alert(uomdata[1]);
                $('#uomname').val(uomdata[1]);
            });
        });
    </script>
}

_UoMLookup

<div class="modal fade" id="uoMLookupTableModal" tabindex="-1" role="dialog" aria-labelledby="uoMLookupTableModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <table id="uoMTable" class="table table-striped table-bordered table-bordered nowrap" style="width:100%">
                    <thead>
                        <tr>
                            <td>Id</td>
                            <td>Name</td>
                            <td>Description</td>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (UoM uom in Model.UoMs)
                        {
                            <tr>
                                <td class="uom-id">@uom.Id</td>
                                <td class="uom-name">@uom.Name</td>
                                <td>@uom.Description</td>
                            </tr>
                        }
                    </tbody>
                </table>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-light" data-dismiss="modal">Cancel</button>
                <button id="getUoM" type="button" class="btn btn-success" data-dismiss="modal">Select</button>
            </div>
        </div>
    </div>
</div>

ItemCreateViewModel

using CRMandOMS.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace CRMandOMS.ViewModels
{
    public class ItemCreateViewModel
    {
        [Required]
        [MaxLength(100, ErrorMessage = "Name cannot exceed 100 characters")]
        public string Name { get; set; }

        [Required(ErrorMessage = "{0} is required")]
        [Range(1000, 999999999)]
        public int Price { get; set; }

        [Required]
        public Guid UoMId { get; set; }
        public IEnumerable<UoM> UoMs { get; set; }

        public string PhotoPath { get; set; }
    }
}
2 Answers

In the HTTP POST Create method (ItemController) if the model is not valid (so ModelState.IsValid == false) you are not passing a model to your View. Ensure passing a valid model, as shown in the controller methods tutorial.

But when the form is submitted with one or some or all of the fields not filled in, it supposed to give some error message that the fields are required. But it didn't and it shows this error.

You do not have a reference to validation scripts, make sure you have _ValidationScriptsPartial.cshtml in Shared folder, then modify your code:

@section scripts {
  @{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
  <script>
  //...
  </script>
}

For the error on your page, just like other community has said, it is likely that the model state is invalid and it execute return View() without returning any data to create view.

However,your partial view does not allow the Model.UoMs to be null.

In your Create Post action, if the model contains UoMs, you could just use

return View(model)

otherwise ,assign UoMs data to model like what you have done in Create Get action, then return it to view.

You could always use a breakpoint on the Post action to debug the result.

Related