點這裡進入ABP系列文章總目錄
基于DDD的現代ASP.NET開發架構--ABP系列之17、ABP應用層——參數有效性驗證
ABP是“ASP.NET Boilerplate Project (ASP.NET樣闆項目)”的簡稱。
ABP的官方網站:http://www.aspnetboilerplate.com
ABP在Github上的開源項目:https://github.com/aspnetboilerplate
應用程式的輸入資料首先應該被檢驗是否有效。輸入的資料能被使用者或其他應用程式送出。在Web應用中,通常進行2次資料有效性檢驗:包括用戶端檢驗和服務端檢驗。用戶端的檢驗主要是使使用者有一個好的使用者體驗。 首先最好是在用戶端檢驗其表單輸入的有效性并且展示給用戶端的那些字段輸入是無效的。但是,伺服器端的校驗是更關鍵和不可缺失的(不要隻做用戶端檢驗而不做伺服器端檢驗)。
伺服器端的檢驗通常是被應用服務(層)執行,應用服務(層)中的方法首先檢驗資料的有效性,然後才使用這些通過驗證的資料。ABP的基礎設施提供了自動檢驗輸入資料有效性的方法。
應用服務(層)方法得到一個資料傳輸對象(DTO)作為輸入。ABP有一個IValidate的接口,DTO通過實作這個接口能夠檢驗資料的有效性。由于IInputDto擴充自IValidate,是以你可以直接實作IInputDto 接口來對資料傳輸對象(DTO)檢驗其有效性。
使用資料注解
ABP提供資料注解的特性。假設我們正在開發一個建立任務的應用服務并且得到了一個輸入,請看下面示例:
public class CreateTaskInput : IInputDto
{
public int? AssignedPersonId { get; set; }
[Required]
public string Description { get; set; }
}
在這裡,Description 屬性被标記為 Required。AssignedPersonId 是可選的。在 System.ComponentModel.DataAnnotations 命名空間中,還有很多這樣的特性 ( 例如: MaxLength, MinLength, RegularExpression 等等 )。
在System.ComponentModel.DataAnnotations 命名空間中,請看Task application service 的實作
public class TaskAppService : ITaskAppService
{
private readonly ITaskRepository _taskRepository;
private readonly IPersonRepository _personRepository;
public TaskAppService(ITaskRepository taskRepository, IPersonRepository personRepository)
{
_taskRepository = taskRepository;
_personRepository = personRepository;
}
public void CreateTask(CreateTaskInput input)
{
var task = new Task { Description = input.Description };
if (input.AssignedPersonId.HasValue)
{
task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
}
_taskRepository.Insert(task);
}
}
正如你所看到的,這裡沒有寫任何的資料驗證性代碼(指對Description屬性的驗證)因為ABP會自動去檢驗資料的有效性。ABP也會檢驗輸入資料是否為null。如果為空則會抛出AbpValidationException 異常。是以你不需要寫檢驗資料是否為null值的代碼。如果有任何屬性的輸入資料是無效的它也會抛出相同的異常。
這個機制近似于 ASP.NET MVC 的驗證功能,注意:這裡的應用服務類不是繼承自Controller,它是用在Web應用的一個普通類。
自定義檢驗
如果資料注解的方式不能滿足你的需求,你可以實作ICustomValidate接口,請看下面示例:
public class CreateTaskInput : IInputDto, ICustomValidate
{
public int? AssignedPersonId { get; set; }
public bool SendEmailToAssignedPerson { get; set; }
[Required]
public string Description { get; set; }
public void AddValidationErrors(List<ValidationResult> results)
{
if (SendEmailToAssignedPerson && (!AssignedPersonId.HasValue || AssignedPersonId.Value <= 0))
{
results.Add(new ValidationResult("AssignedPersonId must be set if SendEmailToAssignedPerson is true!"));
}
}
}
ICustomValidate 接口聲明了一個可被實作的AddValidationErrors方法。這裡我們有一個叫做 SendEmailToAssignedPerson 的屬性。如果該屬性是真,AssignedPersonId 屬性會被檢驗是否有效,否則該屬性可以為空。如果有驗證錯誤,我們必須添加把這些驗證結果添加到結果集合中。(就是将ValidationResult 添加到results)
設定預設值
在檢驗資料有效性後,我們需要執行一個額外的操作來整理DTO參數。ABP定義了一個IShouldNormalize接口,這個接口聲明了一個 Normalize的方法。如果你實作了這個接口,在檢驗資料有效性後,Normalize方法會被調用。假設我們的DTO需要一個排序方向的資料。如果這個Sorting屬性沒有被提供資料,那麼在Normalize我們可以給Sorting設定一個預設值。
public class GetTasksInput : IInputDto, IShouldNormalize
{
public string Sorting { get; set; }
public void Normalize()
{
if (string.IsNullOrWhiteSpace(Sorting))
{
Sorting = "Name ASC";
}
}
}
希望更多國内的架構師能關注到ABP這個項目,也許這其中有能幫助到您的地方,也許有您的參與,這個項目可以發展得更好。
歡迎加QQ群:
ABP架構設計交流群:134710707

ABP架構設計交流2群: 579765441
