- Published on
ASP.NET Core 使用 ActionFilter 驗證 ModelState
下面這個方法基本上只可以應用在 API 上面,如果是返回一個 View 時,可能就不適用
以往我們都會在 action 裡面驗證 ModelState.IsValid
,所以每一個 action 裡面都會多出這一段代碼,其實可以寫一個 ActionFilter
使用 AOP
的方式把這一段代碼給抽離出去,這樣子之後就不用在 action 裡面去檢查 ModelState 了
public IActionResult Index()
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Ok("OK");
}
public IActionResult Contact()
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Ok("OK");
}
- 先建立一個
ModelStateValidActionFilter
class,讓它去實作IActionFilter
public class ModelStateValidActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
- 實作
OnActionExecuting
內容,最簡單的方式就是判斷IsValid
就直接 return 掉,不是的話就回BadRequest
public class ModelStateActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid)
{
return;
}
context.Result = new BadRequestResult();
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
- 不過這樣子前端沒有辦法知道是什麼錯誤,我們可以自定一個回傳的型別來作這件事
public class ResultDto<T> where T : class
{
public IList<ErrorDto> Error { set; get; } = new List<ErrorDto>();
public int Code { set; get; }
public T Result { set; get; }
}
public class ErrorDto
{
public string Message { set; get; }
public string Field { set; get; }
}
- OnActionExecuting 修改成,先從 ModelState 把所有的錯誤和錯誤的欄位找出來,然後放到自定義的回傳型別,然後回傳
public class ModelStateActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid)
{
return;
}
var errors = context.ModelState
.SelectMany(modelState => modelState.Value.Errors
.Select(a => new ErrorDto
{
Field = modelState.Key,
Message = a.ErrorMessage
}))
.ToList();
var result = new ResultDto<dynamic>
{
Code = 400,
Error = errors,
Result = "The data is invalid"
};
context.Result = new OkObjectResult(result);
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
- 在 startup 的 ConfigureServices 註冊到全站的
Filters
services.AddMvc(options =>
{
options.Filters.Add<ModelStateValidActionFilter>();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
- 實際的執行結果