前幾節課我們都是使用標籤來做驗證,但很多時候我並不想多寫這麼多單一用途的標籤
這時候我們就可以直接寫在該Dto裡面
其實有人可能會把驗證邏輯跟商業邏輯寫在一起,但這樣的做法並不好,會顯得程式很雜亂
所以寫到Dto裡是非常適合的地方,以後想找有關資料欄位的事情,就是打開Dto就對了
public class NewsCreateDto : IValidatableObject
{
[Required(ErrorMessage = "標題不可為空")]
public string Title { get; set; }
[Required]
public string Contents { get; set; }
public int DepartmentId { get; set; }
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
public List<IFormFile> Files { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
KcgContext _kcgContext = (KcgContext)validationContext.GetService(typeof(KcgContext));
var findTitle = from a in _kcgContext.News
where a.Title == Title
select a;
if (findTitle.FirstOrDefault() != null)
{
yield return new ValidationResult("已存在相同的新聞標題");
}
if (StartDateTime > EndDateTime)
{
yield return new ValidationResult("開始日期不可大於結束日期");
}
}
}
就如上面的程式碼,我們將標題跟日期的驗證都搬來NewsCreateDto
裡面,當然要額外繼承一個IValidatableObject
接著其他的用法都跟自訂標籤的寫法一樣,唯一不同的是回傳的部分要用yield return
因為這邊是可以回傳複數的驗證結果,所以要用yield
接著我們看結果

不過出現的位置似乎不理想,在最上方綜合驗證的地方,所以我們可以改一下,想出現在個別欄位的地方
yield return new ValidationResult("已存在相同的新聞標題", new[] { nameof(Title) });
yield return new ValidationResult("開始日期不可大於結束日期", new[] { nameof(StartDateTime) });

如此就可以出現在該欄位的下方,而不是最上方
但這樣一來,如果我也想要同樣規則套用在修改的Dto上,不就要寫兩個地方,沒辦法共用了?
這其實可以用抽象化的方式來去寫,就可以不用同時維護兩個地方增加麻煩,如果有人想知道怎麼寫可以留言,或者以後有機會會再提到
範例檔:下載