Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting IEnumerable Error: CS1061 does not contain C# ASP.NET MVC5

I couldn't find a solution for my issue, I have tried many alternatives but I could not resolve it.

I generate my database with the model first, afterwards I have used Scaffolding to generate the Views (Index, Create, Edit, Delete..). The only view (Index) with the model use IEnumerable.

The Index View was :

@model IEnumerable<CAD_CMDBv2.Models.Location>

@{
    ViewBag.Title = "Location's Management";
}

<h2>All Locations</h2>

<p>
    @Html.ActionLink("Create Location", "Create")
</p>

    <table class="table">
         <tr>
              <th>
                    @Html.DisplayNameFor(model => model.Location.site_name)
              </th>
              <th>
                    @Html.DisplayNameFor(model => model.Location.country_name)
              </th>
              <th>
                    @Html.DisplayNameFor(model => model.Location.region_name)
              </th>
              <th></th>
        </tr>

        @foreach(var item in Model) {
            <tr>
                 <td>
                      @Html.DisplayFor(modelItem => item.Location.site_name)
                 </td>
                 <td>
                      @Html.DisplayFor(modelItem => item.Location.country_name)
                 </td>
                 <td>
                      @Html.DisplayFor(modelItem => item.Location.region_name)
                 </td>
                 <td>
                      @Html.ActionLink("Edit", "Edit", new { id = item.Location.location_id }) |
                      @Html.ActionLink("Details", "Details", new { id = item.Location.location_id }) |
                      @Html.ActionLink("Delete", "Delete", new { id = item.Location.location_id })
                 </td>
           </tr>
           }
     </table>

I want to insert an asynchronous form for the datasearch, so that becomes:

@model IEnumerable<CAD_CMDBv2.Models.RechercheLocationViewModel>

@{
    ViewBag.Title = "Location's Management";
}

<h2>All Locations</h2>

<p>
    @Html.ActionLink("Create Location", "Create")
</p>

@using (Html.BeginForm("Search", "Restaurant", FormMethod.Get))
{
    @Html.TextBoxFor(r => r.Recherche)
    <input type="submit" value="Rechercher" />

    <p>Search Results </p>
    if (Model.ListeLocations.Count == 0)
    {
        <p> No Results but you can create it !</p>
    }
    else
    {
        <table class="table">
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Location.site_name)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Location.country_name)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Location.region_name)
                </th>
                <th></th>
            </tr>

        @foreach(var item in Model) {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Location.site_name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Location.country_name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Location.region_name)
                </td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { id = item.Location.location_id }) |
                    @Html.ActionLink("Details", "Details", new { id = item.Location.location_id }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.Location.location_id })
                </td>
            </tr>
        }
        </table>
    }
}

I have modified the model in adding a View Model class to allow in IndexView to take as model the View Model by taking over the parameters Locations and use the Search parameter:

//------------------------------------------------------------------------------
// <auto-generated>
//     Ce code a été généré à partir d'un modèle.
//
//     Des modifications manuelles apportées à ce fichier peuvent conduire à un comportement inattendu de votre application.
//     Les modifications manuelles apportées à ce fichier sont remplacées si le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------

namespace CAD_CMDBv2.Models
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    public partial class Location
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Location()
        {
            this.User = new HashSet<User>();
            this.host = new HashSet<Host>();
            this.client_catia = new HashSet<Client_catia>();
            this.client_smartam = new HashSet<Client_smarteam>();   
        }

        public int location_id { get; set; }
        [Display(Name = "Site's Name")]
        public string site_name { get; set; }
        [Display(Name = "Country's Name")]
        public string country_name { get; set; }
        [Display(Name = "Region's Name")]
        public string region_name { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<User> User { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Host> host { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Client_catia> client_catia { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Client_smarteam> client_smartam { get; set; }    
    }
    public class RechercheLocationViewModel : IEnumerable<Location> {
        public string Recherche {get; set;}
        public Location Location { get; set; }
        public List<Location> ListeLocations;

        public IEnumerator<Location> GetEnumerator()
        {
            return ListeLocations.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ListeLocations.GetEnumerator();
        }
    }   
}

The current Controller

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using CAD_CMDBv2.Models;


namespace CAD_CMDBv2.Areas.Locations.Controllers
{
    public class LocationsController : Controller
    {
        private ModeleDonneesCMDBContext db = new ModeleDonneesCMDBContext();

        // GET: Locations/Locations
        public ActionResult Index()
        {
            var liste =  db.Locations.ToList();
            var listeTriee = liste.OrderBy(t => t.site_name);

            return View(listeTriee);
        }
        ...

But that generates two errors of the same type about IEnumerable in the Index View on the lines:

@Html.TextBoxFor(r => r.Recherche)

And

if (Model.ListeLocations.Count == 0)

I got this error:

CS1061 Error 'IEnumerable' does not contain a definition for 'ListeLocations' and no extension method 'ListeLocations' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference ?)

What does that mean? How can I resolve this? I still have some difficulty with understanding the IEnumerable interface.

like image 719
Jeffrey C. Avatar asked Apr 13 '16 09:04

Jeffrey C.


1 Answers

Your Location class contains the properties Recherche and ListeLocation, but an IEnumerable of that class does not have those properties.

You are using the IEnumerable of the class as an instance of that class, that can't work.

You should think about what you need your model to be, because in one part of the view you use Model as if it were a Location, and in another part (@foreach(var item in Model) {) you use it as an IEnumerable

When you use the IEnumerable interface as a model, you are telling the View you have some kind of list, collection, or something you can 'Enumerate' as a model. A list of your Location objects, so to speak, not a single one.

Edit in response to your comments: Change the @model IEnumerable<CAD_CMDBv2.Models.RechercheLocationViewModel> to CAD_CMDBv2.Models.RechercheLocationViewModel

Then you need yo change the controller Action:

Instead of :

var liste =  db.Locations.ToList();
var listeTriee = liste.OrderBy(t => t.site_name);

return View(listeTriee);

use:

var model = new RechercheLocationViewModel();
model.AddRange(db.Locations.OrderBy(t => t.site_name));

return View(model);

But that won't make it 'work': Your search query cannot take place in the view, you will have to go back to the server for that, so the architecture of your model is not quite right; you don't need all your locations in there, an what the single Location is there for I don't understand as well. If you want to do an async search in the view, you need an AJAX call back to the server that's going to return the search result. Your form is now just going to post something back to a Search action on your controller, and I don't know what that action does.

I can only advice you to study a bit more on creating search forms with AJAX in ASP.NET MVC

like image 51
Stephen Avatar answered Sep 28 '22 09:09

Stephen