Click here to Skip to main content
15,885,164 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
The problem I am running into is using two model classes in one view. I have tried using a class called AllModels as a view model but I get this exception:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[Project2.Models.Entities.ProjectRole]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[Project2.Models.Entities.AllModels]'.
I have looked at many different resources but cannot seem to figure it out for my code. At this point, I am not sure what I am missing or what I am doing wrong. Any help/advice is much appreciated! Thanks.

What I have tried:

Model Classes
public class Person
    {
        public int Id { get; set; }

        [Required]
        [MaxLength(30)]
        public string FirstName { get; set; }

        [Required]
        [MaxLength(30)]
        public string MiddleName { get; set; }

        [Required]
        [MaxLength(30)]
        public string LastName { get; set; }

        [Required]
        public string Email { get; set; }

        public ICollection<ProjectRole> ProjectRoles { get; set; }
    }

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

        [Required]
        [MaxLength(30)]
        public string Name { get; set; }

        [Required]
        public DateTime StartDate { get; set; }

        [Required]
        public DateTime DueDate { get; set; }

        public ICollection<ProjectRole> ProjectRoles { get; set; }
    }

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

        [Required]
        public double HourlyRate { get; set; }

        [ForeignKey("Person")]
        public int PersonId { get; set; }

        [ForeignKey("Project")]
        public int ProjectId { get; set; }

        [ForeignKey("AppRole")]
        public int RoleId { get; set; }

    }
Controller Code
[Authorize(Roles = "Member")]
    public class ProjectRolesController : Controller
    {
        private readonly ApplicationDbContext _context;

        public ProjectRolesController(ApplicationDbContext context)
        {
            _context = context;
        }

        private void PopulateLookups(ProjectRole projectRole)
        {
            var projects = _context.Projects.OrderBy(p => p.Name).ToList();
            ViewBag.ProjectId = projects.Select(p => new SelectListItem
            {
                Value = p.Id.ToString(),
                Text = p.Name,
                Selected = p.Id == projectRole.ProjectId
            });
            var people =
                _context.People.OrderBy(p => p.LastName).ThenBy(p => p.FirstName).ToList();
            ViewBag.PersonId = people.Select(p => new SelectListItem
            {
                Value = p.Id.ToString(),
                Text = $"{p.LastName}, {p.FirstName} {p.MiddleName}",
                Selected = p.Id == projectRole.PersonId,
            });
        }

        public async Task<IActionResult> Index()
        {
            
            return View(await _context.ProjectRoles.ToListAsync());
        }
        //...rest of the code below
    }
And my View code
@model IEnumerable< Project2.Models.Entities.AllModels>



@{
    ViewData["Title"] = "Index";
}

<div class="text-center">
    <a href="/"><button>Home</button></a> |
    <a href="../People"><button>Manage People</button></a> |
    <a href="../People/Report"><button>View People Report</button></a> |
    <a href="../Projects"><button>Manage Projects</button></a> |
    <a href="../Projects/Report"><button>View Project Report</button></a> |
    <a href="../ProjectRoles"><button>Manage Project Role</button></a>
</div>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                Person Name
            </th>
            <th>
                Project Name
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ProjectRole.HourlyRate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ProjectRole.RoleId)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Person.FirstName + " " + item.Person.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Project.Id)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.ProjectRole.HourlyRate)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.ProjectRole.RoleId)
                </td>
                <td>
                    <a asp-action="Edit" asp-route-id="@item.ProjectRole.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ProjectRole.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ProjectRole.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>
Posted
Updated 4-Nov-21 10:25am
Comments
[no name] 4-Nov-21 1:36am    
If you had an "AllModels" class, why didn't you show it? The error says it "doesn't exist", and all the evidence (or lack thereof) confirms that.

1 solution

You could create an object that can have objects added to it. Given the following:
C#
public class Model1
{
    public Model1(){ }
}
public class Model2
{
    public Model2(){ }
}
public class Model3
{
    public Model3(){ }
}

public class ModelBag
{
    public List<object> Models { get; set; }
    public ModelBag ()
    {
        this.Models = new List<object>();
    }

    public void Add(object obj)
    {
        if (obj != null) this.Models.Add(obj);
    }

    public T Get<T>()
    {
        var found = this.Models.OfType<T>().Select(x=>x);
        return (found.Count()>0) ? found.First() : default(T);
    }
}

You can do this:
C#
// create the model bag
ModelBag bag = new ModelBag();

// add a couple of models
bag.Add(new Model1());
bag.Add(new Model2());

// retrieve the desired models
Model1 bagModel1 = bag.Get<Model1>(); // this will return the Model1 iobject
Model3 bagModel3 = bag.Get<Model3>(); // this will return a null value


In the usage example above, you add model1 and model2 to the bag, and attempt to retrieve either one will result in a non-null reference. Because we didn't add a Model3 object to the bag, trying to retrieve it will result in a null reference.

I leave it as an exercise for the programmer to make the ModelBag suit his needs (allow/disallow duplicates of a given object type.

EDIT ==================================

I wrote an article with a more complete code sample.

Multiple Models In a MVC View[^]
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900