Question

I have a SelectList in my action method. The selected value for SelectList is coming from the action method parameter. The action and view are simple like below:

// Recipe Action
 public ActionResult Recipe(int? recipeId)
 {
     ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", recipeId);
     return View(new Recipe());
 }

//Recipe View
 @model RecipeDemo.Models.Recipe

 @Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)

I'm using ActionLink below to call the Recipe action.

@Html.ActionLink("Recipe", "Recipe", "Home", new { recipeId = 2 }, null)

It works like I expect, the DropDownList is showing the selected value as the No. 2 (recipeId = 2) item.

Problem

When I change the Recipe action parameter by using route id, like below:

//Recipe View 
public ActionResult Recipe(int? id)
{
    ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", id);
    return View(new Recipe());
}

//Recipe View (Same View as above)
@model RecipeDemo.Models.Recipe

@Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty) 

And I'm using ActionLink below to call the Recipe action.

@Html.ActionLink("Recipe", "Recipe", "Home", new { id = 2 }, null)

The DropDownList is NOT showing the selected value, (id = 2) item. The selection is instead empty. But I have the correct id value in the SelectList. see below:

enter image description here

Why is this, does anyone know the explanation?

Update:

The model is below:

public class Recipe
{
    public int RecipeID { get; set; }
    public string RecipeName { get; set; }
}
Was it helpful?

Solution

Well that was certainly interesting. After first confirming the issue with the code you provided, I experimented around and believe I have the root cause. Basically, you are using the same variable name way to often and the model binder appears to be getting confused. You have RecipeId in your route, RecipeId in your View Model and RecipeId as the name of your view bag variable. By altering my variable names, the SelectList works as expected.

The primary issue is naming your SelectList RecipeId which matches a property in your model. When you send the new Recipe(), the model binder is attempting to use that value. In your first example, since you have RecipeId defined in the URL, it is getting it from there. In the second example, there is no RecipeId to pull from the URL and it is null in the model.

Controller

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {

        private List<Recipe> Recipes;

        public HomeController()
        {
            Recipes = new List<Recipe>
                {
                    new Recipe {RecipeId = 1, RecipeName = "Test - 1"},
                    new Recipe {RecipeId = 2, RecipeName = "Test - 2"},
                    new Recipe {RecipeId = 3, RecipeName = "Test - 3"},
                };
        }

        public ActionResult Index(int? id)
        {
            ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName", id);
            return View(new Recipe());
        }
    }
} 

Index View

@model MvcApplication1.Models.Recipe

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

 @Html.DropDownList("MyRecipeId", (SelectList)ViewBag.MyList)

Basically, vary your parameter names a little bit more to help prevent the model binder from getting confused and/or pulling information from the wrong place.

You can verify this in your second example by sending this in your return statement:

Return View(New Recipe{RecipeId = 3});

The option value with 3 will be selected regardless of what the actual Id sent was.

EDIT

An even better option would be to do what I said to do as an example above. By changing your Action to this:

public ActionResult Index(int? id)
  {
    ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName");
    return View(new Recipe(RecipeId = id));
   }

You can leave your view unchanged. Now, the SelectList will pull from the model that you are sending.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top