我正在制作我的宠物项目以熟悉 asp.net core mvc。最初,有一个控制器User
负责与用户一起工作(注册、授权、密码更改和退出),还有一个方法Login
负责登录。有一次,我想将控制器的名称从 to 更改为User
,Account
将方法的名称从Login
to更改为Sigin
,并且尽可能地替换链接。基本上我有两个问题:
- 如果需要更改控制器或方法的名称怎么办,然后在整个项目中查找旧名称并更改为新名称(
Startup
设置时的视图、代码、类CookieAuthenticationOptions
) - 如果项目已经发展到 >=10 个控制器并且在每个控制器中 >=5 个方法
HttpGet
,并且您无法记住所有这些控制器,您需要调用其中一个,该怎么办。
这是我解决问题的方法
public static class LinksConstants
{
public static class Account
{
public const String Controller = "Account";
public const String SignUpActionName = "SignUp";
public const String SignInActionName = "SignIn";
public const String ChangePasswordActionName = "ChangePassword";
public const String SignOutActionName = "SignOut";
public static readonly String SignUpLink;
public static readonly String SignInLink;
public static readonly String ChangePasswordLink;
public static readonly String SignOutLink;
static Account()
{
String mask = "/{0}/{1}";
SignUpLink = String.Format(mask , Controller , SignUpActionName);
SignInLink = String.Format(mask , Controller , SignInActionName);
ChangePasswordLink = String.Format(mask , Controller , ChangePasswordActionName);
SignOutLink = String.Format(mask , Controller , SignOutActionName);
}
}
}
public class AccountController : Controller
{
[HttpGet, AllowAnonymous, ActionName(LinksConstants.Account.SignInActionName)]
public async Task<IActionResult> SignInView([FromServices] SignInManager signInManager ,
[FromQuery] String returnUrl = null)
{
//do work
}
}
<div class="clearfix">
<a class="float-right" asp-route-returnUrl="@Model.ReturnUrl" asp-controller=@LinksConstants.Account.Controller asp-action=@LinksConstants.Account.SignUpActionName>Create account</a>
</div>
您如何在实际项目中解决此类问题?
模型
public sealed class SignInViewModel
{
#region Fields
public static readonly SignInViewModel Empty;
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
[Display(Name = "Email")]
public String Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
[Remote(action: LinksConstants.RemoteValidation.ValidationPasswordActionName , controller: LinksConstants.RemoteValidation.Controller)]
public String Password { get; set; }
[ScaffoldColumn(false), ValidateNever]
public String ReturnUrl { get; set; }
#endregion Fields
static SignInViewModel()
{
Empty = new SignInViewModel()
{
ReturnUrl = "/"
};
}
public async Task ValidationOnServer(ModelStateDictionary modelState , UserManager userManager)
{
UserEntity user = await userManager.FindByEmailAsync(Email);
if (user is null || !await userManager.CheckPasswordAsync(user , Password))
{
String message = "Invalid email or password";
modelState.TryAddModelError(nameof(Email) , message);
modelState.TryAddModelError(nameof(Password) , message);
}
}
}
看法
@using WebContacts.Models.Account;
@model SignInViewModel
@section Scripts
{
<partial name="_ValidationScriptsPartial" />
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form id="account" method="post" asp-route-returnUrl="@Model.ReturnUrl">
<div class="container py-0 ">
<div class="row d-flex justify-content-center align-items-center ">
<div class="col-12 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-2-strong" style="border-radius: 1rem;">
<div class="card-body p-5 text-center">
<h3 class="mb-5">Sign in</h3>
<div class="form-outline mb-4">
<input class="form-control form-control-lg" asp-for="@Model.Email" />
<label class="form-label" asp-for="@Model.Email"></label>
<span class="text-danger" asp-validation-for="@Model.Email"></span>
</div>
<div class="form-outline mb-4">
<input class="form-control form-control-lg" asp-for="@Model.Password" />
<label class="form-label" asp-for="@Model.Password"></label>
<span class="text-danger" asp-validation-for="@Model.Password"></span>
</div>
<button class="btn btn-primary btn-lg btn-block" type="submit">Login</button>
<div class="clearfix">
<a class="float-right" asp-route-returnUrl="@Model.ReturnUrl" asp-controller=@LinksConstants.Account.Controller asp-action=@LinksConstants.Account.SignUpActionName>Create account</a>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</body>
</html>
简而言之:您需要自动替换其中的控制器类名和方法名。
Nameof非常适合这个。
唯一要做的就是接受不带后缀的控制器命名,即形式为
Account
,而不是AccountController
。命名约定允许这样做:什么是控制器?.
在标签助手中我们写
一切都很好。
之后,您可以轻松地重命名方法和类。
我意识到这并不能解决所有问题。View 和 ViewModel 的自动重命名问题仍然存在。
IViewLocationExpander
使用视图,您可能会在界面的帮助下搞砸一些事情。我还没有在实际项目中看到这一点,但 Fanie Reynders 的《使用 ASP.NET Core 2 的现代 API 设计》一书中有一个示例,说明如何使用
IApplicationModelConvention
.以此类推,您可以制定自己的 View 命名约定。
保留视图模型。这就是源生成器肯定可以提供帮助的地方。
但恐怕如果这一切都付诸实施,那么那些支持这个项目的人会诅咒你。
我还建议寻找垂直切片架构。放弃传统的放置方式:Controllers 文件夹中的控制器,Views 文件夹中的视图,Models 文件夹中的模型。
相反,根据它们的用途对它们进行分组:在 Account 文件夹中,控制器、模型、视图和其他与帐户相关的东西都位于一起。然后重命名将变得更加容易:无需匆忙浏览不同的文件夹,记住其他地方忘记了一些东西。
但是,这并不能完全解决问题,因为有时需要从一个控制器重定向到另一个控制器。然后,如果您在一个文件夹中更改名称,则必须在另一个文件夹中进行更改。但这仍然很少见。