MVC - 在DropDownListFor中处理空值(NullReferenceException)

时间:2015-05-21 13:33:28

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

我尝试使用MVC5和EF6.1自定义Identity(2.1)。我已经在Identity用户表中添加了一个CountryId,并在CountryId上添加了一个具有FK约束的完整单独的Country表(CountryId,CountryName)。我尝试做一个下拉列表,如果用户过去曾选择用户国家(来自users表中的CountryId),则会选择用户所在国家/地区。但是,如果没有选择,则该值将为空。

我试图完成的逻辑是:

if (Model.Country.CountryName != null) {
    @Html.DropDownListFor(m => m.Country, new SelectList(Model.Countries, "Value", "Text"), Model.Country.CountryName)<br />
} else {
    @Html.DropDownListFor(m => m.Country, new SelectList(Model.Countries, "Value", "Text"), "Select a Country")<br />
}

如果你删除上面的if else语句(它也不起作用),每个DropDownListFor本身都有效,除了前者在CountryName为null时抛出NullRefernceException。后者根本不记得用户过去选择的内容。这是我的控制器:

        var userId = User.Identity.GetUserId();
        ApplicationUser user = await UserManager.FindByIdAsync(userId);
        var model = new IndexViewModel
        {
            HasPassword = HasPassword(),
            //PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
            //TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
            //Or we can write like this because of the user statement above.
            //PhoneNumber = user.PhoneNumber,
            //TwoFactor = user.TwoFactorEnabled,
            Logins = await UserManager.GetLoginsAsync(userId),
            BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
            Country = user.Country,
            State = user.State,
            City = user.City,
            Countries = new SelectList(db.Countries, "CountryId", "CountryName")
        };
        return View(model);

如果我在控制器模型中使用这样的东西:

Countries = new SelectList(db.Countries, "CountryId", "CountryName", user.Country.CountryName)

然后它会在控制器上抛出NullReferenceException。我明白为什么会发生这种情况,但是对于我的生活来说,在半天的搜索后找不到答案。

我只是想知道是否有一种干净的方法来处理空值,因此,如果CountryId为null,则传递一个不同的默认值?

总是非常感谢任何帮助。

编辑:我忘了提及viewmodel。我基本上将所有这些添加到了IndexViewModel中(虽然我不确定此时是否需要它):

    public int CountryId { get; set; }
    public int StateId { get; set; }
    public int CityId { get; set; }

    public virtual Country Country { get; set; }
    public virtual State State { get; set; }
    public virtual City City { get; set; }

    public IEnumerable<SelectListItem> Countries { get; set; }
    public IEnumerable<SelectListItem> States { get; set; }
    public IEnumerable<SelectListItem> Cities { get; set; }

1 个答案:

答案 0 :(得分:0)

首先,您无法将下拉列表绑定到复杂类型。 Html没有关于你的c#Country类的概念。您需要绑定到CountryId属性

@Html.DropDownListFor(m => m.CountryId , Model.Countries)

另请注意,Countries已经是SelectList,因此从它创建另一个SelectList有点无意义和不必要的额外开销,所以它只是Model.Countries,而不是new SelectList(Model.Countries, "Value", "Text") CountryId

接下来,您对属性(CountryId)的绑定以及确定选择了哪个选项的Model.Country.CountryName的值 - 第3个参数(value)将被忽略。但即使它不是,它根本不会选择任何内容,因为您的选项的CountryId属性是CountryName属性的值,而不是CountryId属性。如果存在Country,则需要在控制器中设置if (Model.Country.CountryName != null) {的值。

最后,您的Country会抛出异常,因为null的值为CountryName(您无法访问null对象的if/else属性。

完全不需要@Html.DropDownListFor(m => m.CountryId , Model.Countries, "-Please select-") 块,视图中只需要一行代码

CountryId

如果0的值为intCountryId的默认值),则会选择“-Please select-”选项。如果CountryId的值与集合中的某个值匹配,则在呈现视图时将选择该选项。由于int的类型为IndexViewModel,因此如果用户未选择有效的国家/地区,则会生成验证错误。

最后,尽管States命名,但它不是视图模型!视图模型仅包含在视图中显示/编辑所需的属性,因此应删除您拥有的3个虚拟属性(可能还有与CitiessphereRadiusCGFloat = sphereRadiusFloat.map{CGFloat($0)} 相关的4个属性,但不确定是否刚刚从视图和控制器中省略了一些代码)