尝试将嵌套的ViewModel传递给Partial时出现NullReferenceException

时间:2014-11-19 03:37:39

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

我的登录和注册表单位于同一页面中,它们由制表符元素分隔。

每个表单都有一个ViewModel:

public class RegisterViewModel
{
    public string FullName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
}

public class LoginViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}

由于两个表单都在同一页面上,因此我有一个父ViewModel:

public class LoginAndRegisterViewModel
{
    public LoginViewModel LoginViewModel{ get; set; }
    public RegisterViewModel RegisterViewModel{ get; set; }
}

// Actions...
public ActionResult Register()
{
    return View("Login");
}
public async Task<ActionResult> Register(LoginAndRegisterViewModel model)
{
    // blah.. do stuff here...
    return View("Login", model);
}

但是在主视图中,当我尝试使用表单呈现部分时,我在Model.LoginViewModel和Model.RegisterViewModel中得到System.NullReferenceException(附加信息:对象引用未设置为对象的实例。)。这是观点:

Login.cshtml

@model Models.LoginAndRegisterViewModel
...
@Html.Partial("_LoginPartial", Model.LoginViewModel)
...
@Html.Partial("_RegisterPartial", Model.RegisterViewModel)

我已经看到,通常的做法是遵循这种惯例,详见here in this SO question。我甚至尝试使用this PartialOrNull helper,但我仍然得到例外。我也尝试了基于此的解决方案&#34; Forms for Deep View Model graphs&#34;制品

这也没有用:

@Html.Partial("_LoginPartial", Model.LoginViewModel, new ViewDataDictionary(ViewData){Model = null});

我如何才能拥有这样的注册/登录表?正如我所说的那样,其他SO问题的情况完全相同,并且每个人都报告说该解决方案有效,但那是针对MVC3的

编辑1:添加_LoginPartial作为参考。

@model Models.LoginViewModel

@{
    using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
    {
        @Html.TextBoxFor(m => m.Email)
        @Html.PasswordFor(m => m.Password)
    }
}

编辑2:尝试了?运算符并仍然获得异常。

@Html.Partial("_LoginPartial", Model.LoginViewModel ?? new LoginViewModel())

更新:根据接受的答案,我做了一些测试,现在它没有初始化ViewModel构造函数,也没有在Get操作中发送空的ViewModel。

唯一需要的是将部分视图声明为主模型为@model:

@model Models.LoginAndRegisterViewModel

然后访问部分中的嵌套ViewModel:

@model Models.LoginAndRegisterViewModel

@{
    using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
    {
        @Html.TextBoxFor(m => m.LoginViewModel.Email)
        @Html.PasswordFor(m => m.LoginViewModel.Password)
    }
}

1 个答案:

答案 0 :(得分:2)

您应该在视图模型构造函数

中初始化属性LoginViewModelRegisterViewModel
public class LoginAndRegisterViewModel
{
  public LoginAndRegisterViewModel()
  {
    LoginViewModel = new LoginViewModel();
    RegisterViewModel  = new RegisterViewModel ();
  }
  public LoginViewModel LoginViewModel{ get; set; }
  public RegisterViewModel RegisterViewModel{ get; set; }
}

并在GET方法中传递视图模型的新实例

public ActionResult Register()
{
  var model = new LoginAndRegisterViewModel();
  return View("Login", model);
}

并确保您回溯模型属性,将模型传递给partials

@Html.Partial("_LoginPartial", Model)

并将部分更改为使用LoginAndRegisterViewModel

@model Models.LoginAndRegisterViewModel
@using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
{
  @Html.TextBoxFor(m => m.LoginViewModel.Email)
  @Html.PasswordFor(m => m.LoginViewModel.Password)
}

这可确保控件绑定到视图模型并生成正确的名称属性

<input type="text: name="LoginViewModel.Email"..>

而传递模型的属性会生成

<input type="text: name="Email"..>

在回发后不会绑定到LoginAndRegisterViewModel,所有属性都为null