0

I am using the @Html.dropdownlistfor that allows the user to choose the customer that creates the deal. But the chhosed customer did not proceed to the controller which led to an unvalid model state. I got the reason that the model was not valid

Error

but I did not know how to solve it. I have followed these links but the problem is still the same.

  1. How do I get the Selected Value of a DropDownList in ASP.NET Core MVC App

  2. How to get DropDownList SelectedValue in Controller in MVC

  3. SelectList from ViewModel from repository Asp.net core

Sorry if my question is naive I am new to ASP.net core MVC.

the code is as below:

    namespace MyShop.ViewModels
{
    public class CreateDealVM
    {
        public Deals deal { get; set; }
        public IEnumerable<SelectListItem> CustomerListVM { get; set; }

    }
}

The Model class:

 namespace MyShop.Models
{
    [Table("Deals")]
    public class Deals
    {
        [Key]
        [Display(Name = "ID")]
        public int dealId { get; set; }

        [ForeignKey("Customer")]
        [Display(Name = "Customer")]
        public Customer customer { get; set; }

        [Display(Name = "CustomerName")]
        public string? parentCustomerName { get; set; }

        [Display(Name = "product")]
        public DealTypeEnum product { get; set; }

        [Display(Name = "Date")]
        public DateTime saleDate { get; set; }

        [Display(Name = "Quantity")]
        public float quantity { get; set; }

        [Display(Name = "Price")]
        public float price { get; set; }
    }

The Controller:

  public IActionResult Create()
        {
            CreateDealVM vm = new CreateDealVM();
            vm.CustomerListVM  = _context.Customers.Select(x => new SelectListItem { Value = x.customerId.ToString(), Text = x.customerName }).ToList();
            return View(vm);
        }


        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind("dealId,customer,product,saleDate,quantity,price")] Deals deal, CreateDealVM vm)
        {
    
            if (ModelState.IsValid)
            {
                try
                {
                    vm.deal.customer = _context.Customers.Find(vm.CustomerListVM);

                    vm.deal = deal;
                    _context.Deals.Add(vm.deal);

                    _context.SaveChanges();

                    return RedirectToAction("Index");

                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }


                return View(vm);
            }
            else
            {

                var errors = ModelState.Select(x => x.Value.Errors)
                    .Where(y => y.Count > 0)
                    .ToList();
                    
            //The Error showed here. 
             }
            return View(vm);
        }

The view:

@model MyShop.ViewModels.CreateDealVM
@{
    ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Deals</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
             <div class="form-group">
                @Html.LabelFor(model => model.deal.customer, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.CustomerListVM,Model.CustomerListVM,"Select Customer", htmlAttributes: new { @class = "form-control"})
                </div>
            </div>
            <div class="form-group">
                <label asp-for="deal.product" class="control-label"></label>
                <select asp-for="deal.product" class="form-control"></select>
                <span asp-validation-for="deal.product" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.saleDate" class="control-label"></label>
                <input asp-for="deal.saleDate" class="form-control" />
                <span asp-validation-for="deal.saleDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.quantity" class="control-label"></label>
                <input asp-for="deal.quantity" class="form-control" />
                <span asp-validation-for="deal.quantity" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.price" class="control-label"></label>
                <input asp-for="deal.price" class="form-control" />
                <span asp-validation-for="deal.price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
Alloylo
  • 181
  • 2
  • 12

1 Answers1

1

I just realise your Model is wrong

[Table("Deals")]
    public class Deals
    {
        [Key]
        [Display(Name = "ID")]
        public int dealId { get; set; }

        [ForeignKey("Customer")]
        [Display(Name = "Customer")]
        public int CustomerId { get; set; }

        [Display(Name = "CustomerName")]
        public string? parentCustomerName { get; set; }

        [Display(Name = "product")]
        public DealTypeEnum product { get; set; }

        [Display(Name = "Date")]
        public DateTime saleDate { get; set; }

        [Display(Name = "Quantity")]
        public float quantity { get; set; }

        [Display(Name = "Price")]
        public float price { get; set; }  

        public virtual Customer Customer { get; set; }

Change the Dropdown

 <div class="col-md-10">
                        @Html.DropDownListFor(model => model.Deal.CustomerId,Model.CustomerListVM,"Select Customer", htmlAttributes: new { @class = "form-control"})
                    </div>

one more thing since you have created viewmodel for deal. You only need to do this on your Post Controller

public IActionResult Create()
    {
        CreateDealVM vm = new CreateDealVM();
        vm.CustomerListVM  = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
                              "Id","Text");
        return View(vm);
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Deals deal)
    {
        CreateDealVM vm = new CreateDealVM();
        vm.deal = deal;
        vm.CustomerListVM  = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
                              "Id","Text",VM.CustomerId);

        if (ModelState.IsValid)
        {
            try
            {
                
                _context.Deals.Add(vm.deal);

                _context.SaveChanges();

                return RedirectToAction("Index");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }


            return View(vm);
        }
        else
        {

            var errors = ModelState.Select(x => x.Value.Errors)
                .Where(y => y.Count > 0)
                .ToList();
                
        //The Error showed here. 
         }
        return View(vm);
    }
Yat Fei Leong
  • 751
  • 1
  • 6
  • 10
  • Thanks, @Yat Fei Leong for your response but The problem remains, and the same error still. – Alloylo Sep 07 '22 at 14:24
  • Please check the amended solution. Your Model is wrong. Your Customer should be an Integer that refers to the virtual Customer Table – Yat Fei Leong Sep 07 '22 at 16:21
  • You need to pass the value of customerName together. – Chen Sep 08 '22 at 09:58
  • Is a nullable string name, as long as it includes in the view then it should be in the deal model that passed on Post action – Yat Fei Leong Sep 08 '22 at 10:15
  • I followed the solution and the ModelState.IsValid keeps false. So I used the ModelState.Remove("customer"); to solve the issue. the records were created smoothly in the DB thanks guys for your time. – Alloylo Sep 08 '22 at 12:46