我正在重新考虑我正在进行的项目。在我现有的控制器中,我确实使用了存储库模式,但我仍然执行了一些比我觉得舒服的脚手架更多的脚手架。那个和我的一些控制器可以传入10个以上的存储库(通过Ninject)。所以,我决定引入一个服务层,我的目的是为每个控制器提供一个服务,而每个服务都会将多个存储库注入其中并完成我需要的工作。到目前为止,这种方法很有效,但我遇到了各种各样的混乱:如何将模型验证从控制器移到服务层?
例如,在我的Edit
上查看此OfficesController
方法:
[HttpPost]
public async Task<RedirectToRouteResult> Edit(
short id,
FormCollection form,
[Bind(Prefix = "Office.Coordinates", Include = "Latitude,Longitude")] Coordinate[] coordinates) {
if (id > 0) {
Office office = await this.OfficesService.GetOfficeAsync(id);
if ((office != null)
&& base.TryUpdateModel(office, "Office", new string[2] {
"Name",
"RegionId"
}, form)
&& base.ModelState.IsValid) {
this.OfficesService.UpdateOfficeAsync(office, coordinates);
}
return base.RedirectToAction("Edit", new {
id = id
});
}
return base.RedirectToAction("Default");
}
与控制器的方法相比,它的问题是我仍然从数据库中获取Office
对象,进行更新,验证它,然后再次保存。在这种情况下,复杂性增加而不是减少。之前,我在方法中调用了存储库,现在我调用调用存储库的服务来执行相同的功能。到目前为止,这种复杂性的增加只能在我的Edit
方法中表现出来,在其他地方,复杂性大幅下降,这就是我想要的。
那么,什么是适当的方式移动验证,现在我考虑一下,模型更新逻辑从控制器到服务?建议表示赞赏!
供参考,以下是我的项目结构:
FindTechnicians()
或FindActive()
等答案 0 :(得分:2)
如果您还没有,请阅读以下2篇文章:
您的问题的答案是FluentValidation.NET和依赖装饰。
有了它,你可以这样做:
private readonly IExecuteCommands _commands;
[HttpPost]
public async Task<RedirectToRouteResult> Edit(short id, UpdateOffice command) {
// with FV.NET plugged in, if your command validator fails,
// ModelState will already be invalid
if (!ModelState.IsValid) return View(command);
await _commands.Execute(command);
return RedirectToAction(orWhateverYouDoAfterSuccess);
}
该命令只是一个简单的DTO,就像一个viewmodel。可能看起来像这样:
public class UpdateOffice
{
public int OfficeId { get; set; }
public int RegionId { get; set; }
public string Name { get; set; }
}
...和魔法验证器:
public class ValidateUpdateOfficeCommand : AbstractValidator<UpdateOffice>
{
public ValidateUpdateOfficeCommand(DbContext dbContext)
{
RuleFor(x => x.OfficeId)
.MustFindOfficeById(dbContext);
RuleFor(x => x.RegionId)
.MustFindRegionById(dbContext);
RuleFor(x => x.Name)
.NotEmpty()
.Length(1, 200)
.MustBeUniqueOfficeName(dbContext, x => x.OfficeId);
}
}
如果您已为依赖项注入设置了验证器并且您正在使用FV MVC验证提供程序,那么每个验证规则都将在您的操作方法执行之前运行。如果存在验证错误,则ModelState.IsValid将为false。
您刚刚解决了控制器和(可能)服务层中的过度注入问题。您可以运行任何查询,执行任何命令,或验证只有3个接口依赖项的任何对象。