MVC结构查询
本文关键字:查询 结构 MVC | 更新日期: 2023-09-27 18:08:00
晚上,我追逐我的尾巴试图得到一个简单的ASP的结构。NET MVC正确。从一开始我就应该说我对ASP和MVC完全陌生,我以前用过一点c#。
举例来说,假设我正在尝试检查两个信息,例如用户输入的用户名和密码,与存储所有用户信息的数据库。如果他们输入了正确的凭据,则会显示用户信息的摘要,如果没有,则会被带回到登录页面(视觉上永远不会离开),并提示请再试一次。
所以我有我的主页(登录页)视图,HomeController
和HomeIndexViewModel
。同样,我有一个帐户视图,一个AccountController
和一个AccountUserViewModel
(也有AccountIndexViewModel
,但这并没有真正使用)。
Home视图"接受"(通过它的控制器)一个HomeIndexVM
作为它的模型:
@model ViewModels.HomeIndexViewModel
@using (Html.BeginForm("User", "Account", FormMethod.Post))
{
if (@Model.PreviousAttempts)
{
<p><b>Username or password were not recognised please try again.</b></p>
}
<p>Username: @Html.TextBoxFor(x => x.Username)</p>
<p>Password: @Html.PasswordFor(x => x.Password)</p>
<input id="btnLogin" type="submit" value="Login" />
}
HomeController:
public class HomeController : Controller
{
public ActionResult Index(bool invalidLogin = false)
{
var vm = new HomeIndexViewModel() { Username = string.Empty, Password = string.Empty, PreviousAttempt = invalidLogin };
return View(vm);
}
}
最后是HomeIndexViewModel.cs
public class HomeIndexViewModel
{
public string Username { get; set; }
public string Password { get; set; }
public bool PreviousAttempt { get; set; }
}
我认为到目前为止还可以。现在点击登录按钮,它将发布到Account, User。
public ActionResult User(UserLogin userLogin)
{
if (!ModelState.IsValid)
return RedirectToAction("Index", "Home", new { invalidLogin = true });
// Match username and password against database
User user = userLogin.IsValid(userLogin.Username, userLogin.Password);
if (user != null)
{
return this.View(user);
}
return RedirectToAction("Index", "Home", new { invalidLogin = true });
}
这里有几件事,您可以看到重定向回到登录页面,带有true标志,以显示登录失败消息。
但更重要的是,显然它不会工作,因为它需要一个UserLogin
作为参数。这是一个模型对象,包含:
public class UserLogin
{
private NewDBSolution_v1Entities accountsDB = new NewDBSolution_v1Entities();
[Required, MinLength(2)]
public string Username { get; set; }
[DataType(DataType.Password), Required]
public string Password { get; set; }
public bool PreviousAttempts { get; set; }
public User IsValid(string username, string password) // Ideally use the local username and password properties rather than pass in as they are the same.
{
// Match username and password against database and return full user info if match found, otherwise return null
}
}
所以我在问什么…在这种情况下,帐户的用户操作采取HomeIndexViewModel
,即使它是Home而不是帐户相关,这是最佳实践吗?或者我应该像我最初做的那样传递一个模型对象,并将其用于验证(我不喜欢的是验证是在从不同视图传递的对象中完成的,如果这有意义的话?)
如何最好地将信息从视图捆绑到Action?我意识到vm和模型对象编译器并不关心他们只是类,但我想得到我的关注点分离正确。
基本上这里所有我需要的是用户名和密码从Home视图,应该捆绑在一个VM或M?
在我看来,有很多类可能只是稍微不同,所以为什么不创建一个并使用它呢?我想这就是继承的由来,但如果每个子类只添加一个不同的属性,你会得到很多吗?
无论如何,我一直在兜圈子,关于最好的结构方式。我确实在某个地方读到过,vm基本上应该是模型上的掩码/适配器,这样视图只能看到它需要的东西。但是这些虚拟机没有与它们相关联的模型。
我现在有点漫无目的了,如果有人能弄明白这一点,给我一些指点,我将非常感激,谢谢。
我认为你可能在兜圈子,因为你已经创建了登录视图在HomeController
。登录代码是与account相关的,所以为什么不把它放在AccountController
中呢?
AccountController
中。我会将执行数据库检查的代码移到一个单独的类中,而不是将其保留在模型中。也许是会员资格提供者之类的。我将把该提供程序传递给控制器——这允许控制器和模型对象不再担心如何决定用户是否有效。他们可以让提供者告诉他们。保持实体(无论是UI还是域)简单通常是一种好做法。它们当然应该包含数据库连接对象。
你的控制器看起来像这样:
public class AccountController : Controller
{
private readonly IMembershipProvider membershipProvider;
public AccountController(IMembershipProvider membershipProvider)
{
this.membershipProvider= membershipProvider;
}
public ActionResult Login()
{
var viewModel = new LoginViewModel();
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
var user = membershipProvider.Find(viewModel.Username, viewModel.Password);
if (user != null)
{
membershipProvider.SignIn(user, true);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("Login", "Your credentials were not recognised. Please try again.");
return View(viewModel);
}
}
因为Login操作对于Get和Post都具有相同的名称,所以视图变得更简单。你会在Views/Account文件夹中有一个Login.cshtml
视图,如下所示:
@model ViewModels.LoginViewModel
@using (Html.BeginForm())
{
@Html.AntiForgeryToken() // good practice to add this, ties in with the ValidateAntiForgeryToken attribute on the Post action
@Html.ValidationSummary() // displays model errors if there are any
<p>Username: @Html.TextBoxFor(x => x.Username)</p>
<p>Password: @Html.PasswordFor(x => x.Password)</p>
<input id="btnLogin" type="submit" value="Login" />
}
要回答这个特定的问题:
如何最好地将信息从视图捆绑到Action?
如果可以的话,让默认的模型绑定器来处理。它非常强大,可以处理从表单传回的数据的大多数情况。所有模型绑定器所做的就是匹配表单集合中的名值对,表单集合是在表单发送到类的属性时传回的。如果您的类具有字符串属性Username
和Password
,则模型绑定器将填充它们。就模型绑定器而言,您提供的实际类是无关的。这将同样有效(但其他参与项目的人不会为此感谢你!):
public class Dave
{
[Required, MinLength(2)]
public string Username { get; set; }
[DataType(DataType.Password), Required]
public string Password { get; set; }
}
然后在Post动作中:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Dave dave)
{
...
}
有帮助吗?