-1

I have the following in my controller:

using System.Collections.Generic;
using System.Configuration;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using ContactReport_MVC.Models;

namespace ContactReport_MVC.Controllers
{
    public class ReportsController : Controller
    {
        private ReportDBContext db = new ReportDBContext();

        // GET: Reports
        public ActionResult Index()
        {
            return View(db.Reports.ToList());
        }

        // GET: Reports/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Report report = db.Reports.Find(id);
            if (report == null)
            {
                return HttpNotFound();
            }
            return View(report);
        }

        // GET: Reports/Create
        public ActionResult Create()
        {
            var model = new Report();
            model.ContactsList = GetContacts();
            return View(model);
        }

        // POST: Reports/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Report report)
        {
            if (ModelState.IsValid)
            {
                db.Reports.Add(report);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            var model = new Report();
            return View(model);
        }

        // GET: Reports/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Report report = db.Reports.Find(id);
            if (report == null)
            {
                return HttpNotFound();
            }
            return View(report);
        }

        // POST: Reports/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,Contacts,MeetingDate,SubmittedBy,ClientType,Location,ContactName,Purpose,Discussed,Actions")] Report report)
        {
            if (ModelState.IsValid)
            {
                db.Entry(report).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(report);
        }

        // GET: Reports/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Report report = db.Reports.Find(id);
            if (report == null)
            {
                return HttpNotFound();
            }
            return View(report);
        }

        // POST: Reports/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Report report = db.Reports.Find(id);
            db.Reports.Remove(report);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private static List<SelectListItem> GetContacts()
        {
            List<SelectListItem> items = new List<SelectListItem>();
            string constr = ConfigurationManager.ConnectionStrings["650sContactReportConnectionString"].ConnectionString;
            using (SqlConnection con = new SqlConnection(constr))
            {
                string query = @"SELECT  TOP 1000   e.DisplayEmployeeId as [Id], EmployeeDescNoID as [Name]
                                FROM [Cascade].[dbo].[Employee] e
                                join [Cascade].[dbo].[EmployeeJobs] ej on e.employeeid = ej.EmployeeId
                                Where
                                (e.leftdate is null 
                                and ej.sys_ActiveJob = 1)
                                order by surname asc";
                using (SqlCommand cmd = new SqlCommand(query))
                {
                    cmd.Connection = con;
                    con.Open();
                    using (SqlDataReader sdr = cmd.ExecuteReader())
                    {
                        while (sdr.Read())
                        {
                            items.Add(new SelectListItem
                            {
                                Text = sdr["Name"].ToString(),
                                Value = sdr["Id"].ToString()
                            });
                        }
                    }
                    con.Close();
                }
            }

            return items;
        }
    }
}

If I try to post the form using this (at /Reports/Create), I get the following error:

System.InvalidOperationException: 'There is no ViewData item of type 'IEnumerable' that has the key 'Contacts'.'

I can get around this by putting this into my controller: report.ContactsList = new List<SelectListItem>(); but then my dropdown list shows up as empty.

My HTML helper looks like this:

@Html.DropDownListFor(model => model.Contacts, Model.ContactsList, new { @class = "form-control js-data", @multiple = "multiple", @placeholder = "Type here to search, press enter or tab to select" })

I guess I am asking how to pass the populated list from the Controller's Create method, into the Post method so that it can be commited to the database.

Also how do I store the value of the list (multiple select drop-down list) into the string field defined in the model as Contacts?

Model code:

 public class Report
 {
        public int Id { get; set; }

        [Required]
        [Display(Name = "Relevant Contacts")]
        public string Contacts { get; set; }

        [Required]
        [Display(Name = "Date of meeting")]
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        public DateTime MeetingDate { get; set; }

        [Required]
        public string CompanyName { get; set; }
        [Display(Name = "Submitted By")]

        public string SubmittedBy { get; set; }

        [Required]
        [Display(Name = "Client Type")]
        public string ClientType { get; set; }

        [Required]
        [Display(Name = "Location of meeting")]
        public string Location { get; set; }

        [Required]
        [Display(Name = "Client Contact(s)")]
        public string ContactName { get; set; }

        [Required]
        [Display(Name = "Purpose of meeting")]
        public string Purpose { get; set; }

        [AllowHtml]
        [Required]
        [Display(Name = "What was discussed")]
        [Column(TypeName = "varchar(MAX)")]
        public string Discussed { get; set; }

        [AllowHtml]
        [Required]
        [Display(Name = "Actions to take")]
        [Column(TypeName = "varchar(MAX)")]
        public string Actions { get; set; }

        [NotMapped]
        public IEnumerable<SelectListItem> ContactsList { get; set; }

}

public class ReportDBContext : DbContext 
{
        public DbSet<Report> Reports  { get; set; }

}
Syntax Error
  • 1,600
  • 1
  • 26
  • 60
  • Never ever post the partial code of any method. your codes are incomplete. Add the full code of your Post method. – TanvirArjel Jul 18 '18 at 14:32
  • Also add the Contact Model class. – TanvirArjel Jul 18 '18 at 14:41
  • I have updated the post method. There is no seperate class for contact. – Syntax Error Jul 18 '18 at 15:17
  • Check my answer below.. – TanvirArjel Jul 18 '18 at 15:18
  • The error means that `ContactsList` is `null` which it will be because you did not repopulate it when you return the view (as you did in the GET method). Refer [this answer](https://stackoverflow.com/questions/34366305/the-viewdata-item-that-has-the-key-xxx-is-of-type-system-int32-but-must-be-o) for a detailed explanation. –  Jul 19 '18 at 00:45
  • However you have multiple other problems. The `Contacts` property must be `IEnumerable` and you must use `@Html.ListBoxFor()` as explained in [this answer](https://stackoverflow.com/questions/40725358/why-does-the-dropdownlistfor-lose-the-multiple-selection-after-submit-but-the-li/40732481#40732481) –  Jul 19 '18 at 00:51

1 Answers1

0

Your View needs a list of contacts to fill the combo. You can put it in the model Report but that is a bad design.

To not pollution your model, you can create a ViewModel like CreateReportViewModel

public class Report
{
    public string Contacts { get; set; }
    //other property
}

public class CreateReportViewModel {
    [Required]
    [Display(Name = "Relevant Contacts")]
    public string Contacts { get; set; }

    public IEnumerable<SelectListItem> ContactsList { get; set; }
}

Next, you can map your model to your viewmodel by your-self or a 3rd party (AutoMapper i.e). In the controller, you fill the info necessary for your view

public ActionResult Create()
{
     var reportModel = new CreateReportViewModel();
     //init ContactsList
     reportModel.ContactsList = GetContacts(); //this method retrieves a   list from a database table
}
[HttpPost]
public ActionResult Create(CreateReportViewModel reportModel)
{
    if (ModelState.IsValid)
    {
        var report = new Report();
        report.Contacts = reportModel.Contacts;
        //save to db
    }
    else
    {          
        return View(reportModel);
    }

}
Antoine V
  • 6,998
  • 2
  • 11
  • 34