MVC 5 ViewModel not working as it was in MVC 4
Asked Answered
R

4

7

I will try to get straight to the point. I had some help building a ViewModel here on StackOverflow. It worked fine in MVC 4 but now that I am converting the application to MVC 5 it is not working. Nothing has changed in way of the code. I have a _navigation.cshtml which is a partial that is rendered in my Layout.cshtml and the error is within the For Loops in that Partial. This same code is working fine in MVC 4. Here is the code:

My error is in the partial page during the for loop and I get the error on Ingredient in the line:

@foreach (Ingredient ingredient in Model.Ingredients)

also in the same place on any other for loop in the same place. The error says:

The type or namespace name 'Recipe' could not be found (are you missing a using directive or an assembly reference?)

Here is my code:

Models/Ingredient.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    namespace XXX.Models
    {
        public class Ingredient
        {
            public int IngredientID { get; set; }
            public string IngredientNameEs { get; set; }
        }
    }

Models/Recipe.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    namespace XXX.Models
    {
        public class Recipe
        {
            public int RecipeID { get; set; }
            public string RecipeNameEs { get; set; }
        }
    }

Models/IdentityModel.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration.Conventions;
    using System.Linq;
    using System.Web;
    using Microsoft.AspNet.Identity.EntityFramework;
    using XXX.Models;

    namespace XXX.Models
    {
        // You can add profile data for the user by adding more properties to your ApplicationUser class, 
        // http://go.microsoft.com/fwlink/?LinkID=317594 for more.
        public class ApplicationUser : IdentityUser
        {
        }

        public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
        {
            public ApplicationDbContext(): base("DefaultConnection")
            {
            }

            public DbSet<Ingredient> Ingredients { get; set; }
            public DbSet<Recipe> Recipes { get; set; }

        }
    }

ViewModels/NavigationViewModel.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using XXX.Models;

    namespace XXX.ViewModels
    {
        public class NavigationViewModel
        {
            public IEnumerable<Ingredient> Ingredients { get; set; }
            public IEnumerable<Recipe> Recipes { get; set; }
        }
    }

Controllers/PartialsController.cs

    using XXX.Models;
    using XXX.ViewModels;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Entity;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;

    namespace XXX.Controllers
    {
        public class PartialController : Controller
        {
            private ApplicationDbContext db = new ApplicationDbContext();

             public ActionResult Navigation()
             {
             NavigationViewModel viewModel;

             viewModel = new NavigationViewModel();
             viewModel.Ingredients = db.Ingredients.Where(i => i.IsProduct != false).ToList();
             viewModel.Recipes = db.Recipes.ToList();

             return PartialView("_Navigation", viewModel);
             }
         }
    }

Partials/_Navigation.cshtml (Asterisks indicate error near Ingredient and Recipe in For Loop)

@model XXX.ViewModels.NavigationViewModel
@using XXX.Models
//edited for brevity..
   <li class="has-dropdown">@Html.ActionLink(XXX.Views.Shared.CultureSwap.Products, "Products", "Ingredient")
        <ul class="dropdown">
            @*//From NavigationViewModel print out each Product*@
            @foreach (*Ingredient* ingredient in Model.Ingredients)
            {
                <li><a href="/Ingredient/Products/#@ingredient.IngredientNameEs">@ingredient.IngredientNameEs</a></li>
    }
        </ul>
    </li>

    <li class="divider"></li>
    <li class="has-dropdown">@Html.ActionLink(XXX.Views.Shared.CultureSwap.Recipes, "List", "Recipe")
        <ul class="dropdown">
            @foreach (*Recipe* recipe in Model.Recipes)
            {
                <li><a href="/Recipe/List/#@recipe.RecipeNameEs">@recipe.RecipeNameEs</a></li>
            }
        </ul>
    </li>

Again the errors read:

The type or namespace name 'Ingredient' could not be found (are you missing a using directive or an assembly reference?)

The type or namespace name 'Recipe' could not be found (are you missing a using directive or an assembly reference?)

Here is a screenshot of the error in Visual Studio Next to the same code with no errors:

enter image description here

Rincon answered 11/2, 2014 at 13:10 Comment(3)
You could edit your code instead of delete and repost the questionPerusse
I felt the comments on the typos were confusing. Everything is cleaned up now. I deleted the post so there would not be a duplicate. But this is unconstructive at this point.Rincon
Have you tried adding the namespace of the viewmodel ?Tyeshatyg
M
5

Your view doesn't know where Ingredient or Recipe come from, you need to add a reference to the namespace which those types are under, add @using XXX.Models to the top of your view

@model XXX.ViewModels.NavigationViewModel
@using XXX.Models
...
@foreach (Ingredient ingredient in Model.Ingredients)
{
    ...
}

On a side-note you appear to have a half-baked view model implementation. In your NavigationViewModel you are referencing, which appear to be, domain models. It's generally recommended that anything exposed via a view model, is in actual fact, a view model itself. So in your case, I would introduce a couple of new view models to represent an Ingredient / Recipe i.e.

public class IngredientViewModel
{
    ...
}

public class RecipeViewModel
{
    ...
}

public class NavigationViewModel
{
    public IEnumerable<IngredientViewModel> Ingredients { get; set; }
    public IEnumerable<RecipeViewModel> Recipes { get; set; }
}

These would be be created under the XXX.ViewModels which would mean your view would look like

@using XXX.ViewModels
@model NavigationViewModel

...
Muckrake answered 11/2, 2014 at 13:14 Comment(11)
It did remove the error in the code view and correctly color the Ingredient and Recipe text, but I still get the error at run time.Rincon
Is XXX.Models a separate class lib project or is it compiled into the website? Try a clean/build.Muckrake
XXX.Models is my Models folder. Everything is in one project.Rincon
@EricB you are using a NavigationViewModel, from that model you are referencing Ingredient/Recipe which are coming from XXX.Models. You should create IngredientViewModel/RecipeViewModel and reference those from NavigationViewModel instead. If the models are there then the using is all you should need.Muckrake
Any possibility you could update your answer with an example?.Rincon
Is there something wrong wth the implementation that ROwan gave me here: #20184923Rincon
What about the PartialControler (ActionResult) and what do I put within the RecipeViewModel and IngredientViewModel I have simply put the following line in each:Rincon
public IEnumerable<Ingredient> Ingredients { get; set; }Rincon
public IEnumerable<Recipe> Recipes { get; set; }Rincon
But what changes do I make to my Controler now?Rincon
I thank you for helping, but without further instructions I don't understand and I'm simply taking stabs in the dark. Rowan had what I felt was a good solution and I thought it should work fine in MVC 5 as well. Whats happened between versions that this is no longer a valid way to do things?Rincon
S
6

There is a web.config file located in the Views directory. In it the namespaces that should be available for the views are listed. Did you add a namespace to the views web.config in your mvc4 proj that you are now missing in the mvc5 proj?

The listing in the views web.config is a kind of global using statements that applies to all views.

Sargassum answered 11/2, 2014 at 13:13 Comment(3)
Let me check, I thought I did.Rincon
Would I add XXX.Models or XXX.ViewModels.RecipeLineViewModel ? I added the first and my error changed to The model item passed into the dictionary is of type (System.Collections.Generic.List)1[GransabanaUSA.Models.Recipe], but this dictionary requires a model item of type (GransabanaUSA.ViewModels.RecipeLineViewModel).Rincon
Look in your mvc4 project and try to do the same. That error message looks like something else is wrong. Are you passing in the wrong model from your controller?Sargassum
M
5

Your view doesn't know where Ingredient or Recipe come from, you need to add a reference to the namespace which those types are under, add @using XXX.Models to the top of your view

@model XXX.ViewModels.NavigationViewModel
@using XXX.Models
...
@foreach (Ingredient ingredient in Model.Ingredients)
{
    ...
}

On a side-note you appear to have a half-baked view model implementation. In your NavigationViewModel you are referencing, which appear to be, domain models. It's generally recommended that anything exposed via a view model, is in actual fact, a view model itself. So in your case, I would introduce a couple of new view models to represent an Ingredient / Recipe i.e.

public class IngredientViewModel
{
    ...
}

public class RecipeViewModel
{
    ...
}

public class NavigationViewModel
{
    public IEnumerable<IngredientViewModel> Ingredients { get; set; }
    public IEnumerable<RecipeViewModel> Recipes { get; set; }
}

These would be be created under the XXX.ViewModels which would mean your view would look like

@using XXX.ViewModels
@model NavigationViewModel

...
Muckrake answered 11/2, 2014 at 13:14 Comment(11)
It did remove the error in the code view and correctly color the Ingredient and Recipe text, but I still get the error at run time.Rincon
Is XXX.Models a separate class lib project or is it compiled into the website? Try a clean/build.Muckrake
XXX.Models is my Models folder. Everything is in one project.Rincon
@EricB you are using a NavigationViewModel, from that model you are referencing Ingredient/Recipe which are coming from XXX.Models. You should create IngredientViewModel/RecipeViewModel and reference those from NavigationViewModel instead. If the models are there then the using is all you should need.Muckrake
Any possibility you could update your answer with an example?.Rincon
Is there something wrong wth the implementation that ROwan gave me here: #20184923Rincon
What about the PartialControler (ActionResult) and what do I put within the RecipeViewModel and IngredientViewModel I have simply put the following line in each:Rincon
public IEnumerable<Ingredient> Ingredients { get; set; }Rincon
public IEnumerable<Recipe> Recipes { get; set; }Rincon
But what changes do I make to my Controler now?Rincon
I thank you for helping, but without further instructions I don't understand and I'm simply taking stabs in the dark. Rowan had what I felt was a good solution and I thought it should work fine in MVC 5 as well. Whats happened between versions that this is no longer a valid way to do things?Rincon
D
0

Your view doesn't know where Ingredient or Recipe come from, you need to add a reference to the namespace which those types are under, add @using XXX.Models to the top of your view.

Davenport answered 31/10, 2016 at 10:19 Comment(0)
M
0

If your MVC application has Areas, check whether the namespace of the ViewModel and model reference in the Razor view is matched or not.

If the namespace of the view model contains Areas e.g. Areas.WebApp.Models , that view model won't be compiled in the view when you write @model WebApp.Models.

Both should match. So either remove Areas from ViewModel namespace or add the same fully qualified name in the View.

Mountain answered 6/3, 2020 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.