簡要說明
本文主要介紹Automapper與Validation的使用方法。首先使用Automapper的目的是引入組件完成entity與dto之間的轉換以達到簡化代碼的目的。Abp vnext的項目中已經默認添加好此組件了【介紹】,本文只是說一些簡單的用法,更進一步的使用需要到automapper的官網中查看文檔
其次是Validation主要是用於入參校驗,通過對dto標注相應的屬性達到入參校驗的功能。【abp介紹】【官方介紹】
具體步驟
1、Automapper的基礎使用方法,在官方的文檔中也有比較清晰的說明,所以就只是簡單的根據官方文檔寫一次。然后試運行一下簡單的效果即可。
添加相應的mapper使用的Dto,如UserDto,定義好可以對外輸出的屬性。
public class UserDto: EntityDto<Guid>
{
/// <summary>
/// 用戶名稱
/// </summary>
public string user_name { get; set; }
/// <summary>
/// 用戶手機號
/// </summary>
public string user_phone { get; set; }
/// <summary>
/// 用戶狀態
/// </summary>
public int user_status { get; set; }
}
其次在AbpVnext.Learn.Application中找到LearnApplicationAutoMapperProfile類,添加我們需要的mapper,CreateMap<User, UserDto>();
最后在UserAppServices里面添加以下代碼,其中ObjectMapper.Map就是轉換的方法。
public async Task<UserDto> LoginByUserPhoneAndPwd(string user_phone,string pass_word)
{
var user= await _repository.FindAsync(a=>a.user_phone== user_phone&&a.pass_word== pass_word&&a.user_status==0);
return ObjectMapper.Map<User, UserDto>(user);
}
調試代碼,輸出結果如下,轉換正常:
2、接下來主要介紹一下Validation的用法,官方的Validation是一個簡單與輕量化的組件,主要用數據注解的方式對入參字段的合法性校驗上。下面我們先來做一個簡單的例子,原來登錄接口的入參的參數增加以下[Required]
/// <summary>
/// 登錄的Dto
/// </summary>
public class LoginDto:
{
/// <summary>
/// 用戶手機號
/// </summary>
[Required]
public string user_phone { get; set; }
/// <summary>
/// 登錄密碼
/// </summary>
[Required]
public string pass_word { get; set; }
}
然后調試代碼,測試相應接口,如下圖拋出500異常,
再看日志,顯示的是校驗失敗異常,則表明我們的注解生效了。
3、上面雖然顯示我們的校驗生效了,但是輸出的結果明顯不是我們想要的結果。一般我們需要為校驗失敗的入參輸出統一的code和相應的字符串,讓我們的提示比較清晰明了,同時也讓前端開發的同事比較明確的知道這個是由於參數校驗引起的問題,然后去修正相關參數。因此,我們需要替換掉abp的原有校驗異常輸出。
首先我們查看官方文檔有說明,校驗異常統一為AbpValidationException 。
因此我們在原來的LeanGlobalExceptionFilter中攔截此類型的異常,並將輸出修改為code=100,如下:
public void OnException(ExceptionContext context)
{
logger.LogError(new EventId(context.Exception.HResult),
context.Exception,
context.Exception.Message);
if (context.Exception is AbpValidationException)
{
context.Result = new JsonResult(new { ode = 100, msg = context.Exception.Message });
}
else
{
context.Result = new JsonResult(new { code = 500, msg = "系統異常" });
}
context.ExceptionHandled = true;
}
然后我們再來看看調試接口的輸出結果,如下,則表明我們的替換是成功了。
4、但是這樣就算成功了嗎?當然不是額,abp所有的校驗失敗輸出都是輸出這個:ModelState is not valid! See ValidationErrors for details.這樣的輸出,對我們前端或客戶端同事是非常不友好的輸出,都不知道錯誤原因與相應的字段,因此我們需要進一步去優化這些信息以達到最大程度的減少溝通成本的目的。下面我們來看看如何進行操作吧!
4.1、首先我們看一下注解里面的ValidationAttribute,這個注解包含了字段ErrorMessage是用於輸出校驗錯誤的字段的,所以我們可以好好的利用一下這個ErrorMessage來達到我們的目的。把user_phone的[Required]修改成[Required(ErrorMessage ="手機號碼不能為空")]
4.2、我們回到LeanGlobalExceptionFilter這里,看一下AbpValidationException里面包含了什么信息。
如圖所示,我們看到了ValidationErrors這個字段是一個List,里面包含了我們這一個請求入參的整個dto里所有校驗不通過的信息列表。這樣就好辦了,修改原來的攔截為以下代碼:
public void OnException(ExceptionContext context)
{
logger.LogError(new EventId(context.Exception.HResult),
context.Exception,
context.Exception.Message);
if (context.Exception is AbpValidationException)
{
var validateerros = ((AbpValidationException)context.Exception).ValidationErrors;
context.Result = new JsonResult(new { ode = 100, msg = validateerros.Count > 0 ? validateerros[0].ErrorMessage : context.Exception.Message });
}
else
{
context.Result = new JsonResult(new { code = 500, msg = "系統異常" });
}
context.ExceptionHandled = true;
}
然后調試代碼,並測試相應的接口。現在則表示顯示正常了。至於信息到底是顯示第一個還是最后一個,自己判斷,個人感覺都可以,因為都屬於參數失敗的校驗
4.3、接下來我們使用一下進階的判斷,脫離於單純的字段校驗,如:假如user_phone等於pass_word的時候拋出不能相等提示。這個需要dto繼承IValidatableObject然后增加Validate的實現方法,如下:
public IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
if (user_phone == pass_word)
{
yield return new ValidationResult(
"手機號碼與密碼不能一樣!",
new[] { "user_phone", "pass_word" }
);
}
}
然后調試代碼,並測試相應的接口,如下則表示替換成功了。。