我有一个用户对象:
namespace MySolution.Models
{
public class MyUser
{
public Int32 Id { get; set; }
[Required]
public string CompanyName { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
}
}
Id由SQL Server自动生成。我正在使用Dapper。
所有这些属性都是必需的。但是,我想将其分为两部分 - 因此首先要求用户提供电子邮件 - 然后在下一个“页面”上询问公司名称,名字和名称。姓氏。
[HttpPost]控制器如下所示:
[HttpPost]
public ActionResult SignUp(MyUser myuser)
{
if (ModelState.IsValid)
{
// Insert returns success
if (MyUserRepo.InsertEmailPass(myuser))
{
// Successfully added user, go to next user section
return RedirectToAction("SignUp2", myuser);
}
else
{
// Adding prospect failed
ViewBag.Error = "Email already registered";
}
}
return View(myuser);
}
[HttpPost]
public ActionResult SignUp2(MyUser myuser)
{
if (ModelState.IsValid)
{
// Insert returns success
if (MyUserRepo.UpdateNameCopany(myuser))
{
// Successfully added myuser, go to thank you page
return RedirectToAction("SignUpEnd");
}
else
{
// Adding prospect failed
ViewBag.Error = "Something went wrong";
}
}
}
我想要不显眼的验证和所有内置的MVC功能 - 例如if (ModelState.IsValid)
- 但是,因为我将这个分为2页,所以模型永远不会在第一页上有效 - 除非我手动添加也可以通过电子邮件发送到第二页上的模型(而我需要做的就是对名字,姓氏和公司名称(不是电子邮件)进行SQL更新 - 所以不一定要向SQL添加电子邮件)。
这一切都感觉相当'hacky'。我怎么能这样做,仍然使用内置验证和ModelState等?
我在谷歌上找不到这个。
我的目标是以最少的代码以正确的方式“正确”执行此操作(以及最佳实践?)。
编辑: 我现在有这两个视图模型:
namespace MyNamespace.ViewModels
{
public class SignUpViewModelPage1
{
public int Id { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(50, MinimumLength = 8, ErrorMessage = "{0} must be at least {2} characters long")]
[DataType(DataType.Password)]
public string Password { get; set; }
}
public class SignUpViewModelPage2
{
public int Id { get; set; }
[Required]
public string CompanyName { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
}
控制器:
[HttpPost]
public ActionResult SignUp(SignUpViewModelPage1 svmp1)
{
if (ModelState.IsValid)
{
int Id = senderRepo.InsertEmailPass(svmp1);
// Insert failure returns -1
if (Id != -1)
{
// Successfully added user - go to page 2, pass Id
return RedirectToAction("SignUp2", new { Id = Id });
}
else
{
// Adding user failed - probably duplicate email - tell user & pass invalid model back
ViewBag.Error = "Email already registered";
}
}
return View(svmp1);
}
public ActionResult SignUp2(int Id)
{
return View();
}
[HttpPost]
public ActionResult SignUp2(SignUpViewModelPage2 svmp2)
{
if (ModelState.IsValid)
{
// Insert success returns true
if (senderRepo.UpdateNameCopany(svmp2))
{
// Successfully added user - go to success page
return RedirectToAction("SignUpEnd");
}
else
{
// Adding user failed - tell user
ViewBag.Error = "Email already registered";
}
}
return View();
}
这一切看起来都好吗?任何明显的错误或糟糕的做事方式?
THX
答案 0 :(得分:2)
您的模型应反映您网页上的内容。我会为每个页面创建一个模型,然后进行正常验证。如果需要,我会将结果合并到一个模型中。
答案 1 :(得分:1)
正如其他人所提到的,您应该考虑创建一个代表您的页面输入而不是您的域模型的ViewModel。
从那里,你有几个选择:
1)使用像bootstrap向导这样的东西,它基本上隐藏/显示页面的一部分,直到你提交为止。单个视图模型的所有属性都在您的页面上,但只是由向导隐藏。这也处理验证,非常好的东西。以下是它的示例:Bootstrap Form Wizard Example。您可以找到更多示例和download here。
2)为表单的每一步分解几个较小的ViewModel。
我最近使用了选项1,它对我的项目很有用。
答案 2 :(得分:0)
有不同的方法。如果您希望/需要通过完整页面更新(而不是部分更新)来执行此操作,则需要在 n 部分上拆分模型,其中 n 等于向导你想向你呈现用户。然后,您需要在实际注册用户之前想出一种存储数据的方法。在WebForms时代,我通过保存会话相关数据做了很多事情,这些数据还没有为数据库做好准备但是在往返之间的隐藏字段中。
但是我不推荐这种方法,因为它有点笨拙和过时。更好的方法是将向导步骤设计为部分视图。然后在您的登录页面上指定一个弹出窗口和一个读取Signup
的按钮。有很多JS库提供弹出窗口。我使用臭名昭着的Twitter Bootstrap或jQuery UI,但如果你愿意,还有其他的。因此,当用户点击Signup
时,您将指定的弹出窗口显示第一个局部视图并显示它。您可以通过将AJAX回调到服务器来完成此操作。当然,当前步骤的UI需要提供加载下一步的按钮。您甚至可以为您的模型设计一个局部视图,一次加载它,但根据我们当前所处的步骤显示它的不同部分。
这一切都需要javascript。你可以 - 纠正 - 你应该使用jQuery并通过AJAX请求部分视图。您可以将每个步骤的数据存储在本地javascript变量中。在向导结束时,检查收集的数据并对注册方法进行另一次AJAX调用。在服务器端,您不必更改模型并留下注释。
您可以使用AJAX,jQuery,部分视图等进行谷歌搜索。互联网上充满了关于这个主题的信息。