带有null selectList参数的{Html.DropDownListFor

时间:2016-03-30 18:48:10

标签: c# asp.net asp.net-mvc

这是在创建新控制器时从VS Add New Scaffolded Item...获取的。

在控制器中:

// GET: Drivers/Create
public ActionResult Create()
{
    ViewBag.Tenant = new SelectList(db.Tenants, "TenantID", "TenantName");
    return View();
}

视图然后呈现一个下拉列表:

@Html.DropDownListFor(model => model.Tenant, null, htmlAttributes: new { @class = "form-control" })

相关型号信息:

public partial class Driver
{
    public int DriverID { get; set; }
    public int Tenant { get; set; }
    public virtual Tenant Tenant1 { get; set; }
}

public partial class Tenant
{
    public Tenant()
    {
        this.Drivers = new HashSet<Driver>();
    }

    public int TenantID { get; set; }
    public string TenantName { get; set; }
    public virtual ICollection<Driver> Drivers { get; set; }
}

有人可以解释为什么会这样吗?

我查看了其他问题和文档但找不到答案。我怀疑它是“约定优于配置”的东西,它是使用属性的名称从ViewBag拉出来的。实际上,我将ViewBag属性更改为Tenantz并获得以下异常:

  

没有类型为'IEnumerable'的ViewData项   有关键'租户'。

那么设置ViewBag的属性名称是否与要更新良好实践的模型属性相同?看起来没问题,但我总是听说你应该如何避免ViewBag和动态类型。

1 个答案:

答案 0 :(得分:6)

正如您已经发现的那样,有一个惯例。您视图中的以下行:

@Html.DropDownListFor(model => model.Tenant, null, htmlAttributes: new { @class = "form-control" })

与此行完全相同:

@Html.DropDownList("Tenant", null, htmlAttributes: new { @class = "form-control" })

现在,如果您看一下如何在源代码中实现DropDownList帮助器,您会注意到它只是这样做:

object obj = htmlHelper.ViewData.Eval(name) as IEnumerable<SelectListItem>;

其中name是传递给DropDownList助手的第一个参数。你猜怎么着?它会发现您在控制器中设置的相应值:ViewBag.Tenant = ...

据说使用ViewBag是绝对的,灾难性的,非常糟糕的做法。你已经找到了原因。它可以像狗一样咬你,甚至不知道发生了什么。防止这些狗(ViewBag)的最好方法是在你的解决方案中搜索它们并给它们毒药。只需删除代码中的所有ViewBag调用,并使用视图模型。然后你不会得到不好的惊喜,一切都会有一个合理的解释,在StackOverflow上没有必要这样的问题。

例如,您可以编写普通视图模型:

public class DriverViewModel
{
    public int? SelectedTenantID { get; set; }

    public IEnumerable<SelectListItem> Tenants { get; set; }
}

和一个正常的控制器操作,它将在数据存储区中查询所需信息并将实体模型投影到视图模型:

// GET: Drivers/Create
public ActionResult Create()
{
    var viewModel = new DriverViewModel();
    viewModel.Tenants = new SelectList(db.Tenants, "TenantID", "TenantName");
    return View(viewModel);
}

最后是相应的强类型视图:

@model DriverViewModel
...
@Html.DropDownListFor(
    model => model.SelectedTenantID, 
    Model.Tenants, 
    htmlAttributes: new { @class = "form-control" }
)

在这种情况下,您使用强类型视图,具有强类型视图模型和帮助程序。不再有任何疑虑(和狗咬)。代码是可读的,你不能问,为什么这个约定超过配置正在做这个或那个。因此,只要您的应用程序中没有ViewBag的痕迹,就不会有这样的问题。