ASP.Net MVCのViewBagは1つの穴で、飛び込まないでください

4216 ワード

例えば鵬の学習管理システムはASPを使用する.NetMVC 5が開発したもので、今日の新しいバージョンが発表された後、ウェブサイトにバグが現れ、学生がドロップダウンリストで選択した項目を再ロードして表示したとき、まだ選択されていないことに気づいた.詳しく言えば、このようなアクションがあれば:
public ActionResult Index()
{
List<SelectListItem> persons = new List<SelectListItem>(); 
persons.Add(new SelectListItem { Text = "  ", Value = "qq" });
persons.Add(new SelectListItem { Text = "  ", Value = "rupeng", Selected = true });
ViewBag.persons = persons;
return View();
}

Cshtmlはこうです.
@Html.DropDownList("persons", (IEnumerable)ViewBag.persons)によって生成されるhtmlは、次のようになります.
<select id="persons" name="persons">
<option value="qq">  </option>
<option value="rupeng">  </option>
</select>

2つ目が選択されていないなんて、おかしいでしょう.
DropDownListの2番目のパラメータの「persons」を和「ViewBag」に変更すればよい.personsのpersonsの名前が違うといいです.例えば:@Html.DropDownList("persons1", (IEnumerable)ViewBag.persons)これで正しく生成されます.
<select id="persons1" name="persons1">
<option value="qq">  </option>
<option selected="selected" value="rupeng">  </option>
</select>

  
怪しい!!!
どうする?ソースを見て!DropDownListはSelectExtensions拡張クラスで定義され、DropDownListメソッドは最終的にSelectInternalメソッドを呼び出し、コアコードはこのセグメントです.
if (!flag && obj == null && !string.IsNullOrEmpty(name))
{
obj = htmlHelper.ViewData.Eval(name);
}
if (obj != null)
{
selectList = SelectExtensions.GetSelectListWithDefaultValue(selectList, obj, allowMultiple);
}

  
このnameパラメータはDropDownListに渡された最初のパラメータ「persons」であり、上のコードの主な論理は、まずView Dataで「persons」という名前の値を検索し、View DataとView Bagが同じであることを知っているのでhtmlHelper.ViewData.Eval(name)が取った値は,Indexで定義したList()の集合である.GetSelectListWithDefaultValueメソッドのコードは次のとおりです.
private static IEnumerable<SelectListItem> GetSelectListWithDefaultValue(IEnumerable<SelectListItem> selectList, object defaultValue, bool allowMultiple)
{
IEnumerable enumerable= new object[]
{
defaultValue
};
IEnumerable<string> collection = 
from object value in enumerable
select Convert.ToString(value, CultureInfo.CurrentCulture);

HashSet<string> hashSet = new HashSet<string>(collection, StringComparer.OrdinalIgnoreCase);
List<SelectListItem> list = new List<SelectListItem>();
foreach (SelectListItem current in selectList)
{
current.Selected = ((current.Value != null) ? hashSet.Contains(current.Value) : hashSet.Contains(current.Text));
list.Add(current);
}
return list;
}

  
我々のList()集合はdefaultValueパラメータとしてGetSelectListWithDefaultValueメソッドに渡されることに注意してください(why?)メソッドの内部でdefaultValueをConvertに渡すToString()は、「System」になりました.Collections.Generic.List`1[System.Web.Mvc.SelectListItem]」というもので、GetSelectListWithDefaultValueの主な論理はselectListの中で「System.Collections.Generic.List`1[System.Web.Mvc.SelectListItem]」の値が、见つかると鬼に见えてしまう!!!上記の解析では、cshtmlのDropDownListの最初のnameパラメータとViewBagのいずれかの属性を重複させることはできません.そうしないと、例えば問題があります.
public ActionResult Index()
{
List<SelectListItem> persons = new List<SelectListItem>(); 
persons.Add(new SelectListItem { Text = "  ", Value = "qq" });
persons.Add(new SelectListItem { Text = "  ", Value = "rupeng", Selected = true });
ViewBag.persons = persons;
ViewBag.persons1 = new string[] { };
return View();
}

  
Cshtmlは以下の通りである:@Html.DropDownList("persons1", (IEnumerable)ViewBag.persons)
生成されたhtmlの2番目のデータはselectedされません
マイクロソフトがなぜDropDownListのような簡単なものをこんなに複雑にしたのか分からないが、「書けば書くほど、間違いが多くなる」という言葉を検証している.もちろんマイクロソフトは私たちが間違っていると言って、「It’s not a bug,It’s a feature,by design」と言う理由を与えるかもしれません.シェット!