[英]What is a correct way to implement Fluent Validation for IFormFile
I'm struggling with implementation of validation for IFormFile.我正在努力实现 IFormFile 的验证。 I'm using FluentValidation and here is my validator for FormFile:我正在使用 FluentValidation,这是我的 FormFile 验证器:
public class PhotoValidator : AbstractValidator<IFormFile>
{
private readonly PhotoSettings _settings;
public PhotoValidator(IOptionsSnapshot<PhotoSettings> snapshot)
{
_settings = snapshot.Value;
RuleFor(f => f).NotNull().WithMessage("Please Attach your photo");
RuleFor(f => f.Length).ExclusiveBetween(0, _settings.MaxBytes)
.WithMessage($"File length should be greater than 0 and less than {_settings.MaxBytes / 1024 / 1024} MB");
RuleFor(f => f.FileName).Must(HaveSupportedFileType);
}
private bool HaveSupportedFileType(string fileName)
{
return _settings.IsSupported(fileName);
}
}
The problem is than during request validator isn't called at all, it just skips it.问题在于根本没有调用请求验证器,它只是跳过它。 Here is my api endpoint signatrue:这是我的 api 端点签名:
[HttpPost("{productId:min(1)}")]
public IActionResult Upload([FromRoute] int productId, IFormFile file)
{
// some code here
}
In my project I have other validators (however they don't implement AbstractValidator with Interface type) and they are doing job.在我的项目中,我有其他验证器(但是它们没有实现具有接口类型的 AbstractValidator)并且它们正在工作。 Is it even possible to validate type that implements interface?甚至可以验证实现接口的类型吗?
The problem is than during request validator isn't called at all, it just skips it.问题在于根本没有调用请求验证器,它只是跳过它。
In addition to the manual trigger method, we can indeed let PhotoValidator
function trigger automatically after submit.除了手动触发的方式,我们确实可以让PhotoValidator
function在提交后自动触发。
The premise is that we need to configure FluentValidation in the ConfigureServices method of startup as follow:前提是我们需要在启动的 ConfigureServices 方法中配置 FluentValidation如下:
using FluentValidation;
using FluentValidation.AspNetCore;// this need FluentValidation.AspNetCore dll
//...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddMvc().AddFluentValidation();
services.AddTransient<IValidator<FileData>, PhotoValidator>();
}
Here is a good reference document for your reference.这是一个很好的参考文档供您参考。
Besides, to verify the content of IFormFile
, you need to put it into a class as an object to verify.此外,要验证IFormFile
的内容,您需要将其放入class 作为 object进行验证。
Here I created the FileData
class and stored a field of IFormFile type as follows:这里我创建了FileData
class 并存储了一个 IFormFile 类型的字段如下:
public class FileData
{
public IFormFile file { get; set; }
}
And, there are some details that need to be modified when verifying in PhotoValidator.并且,在 PhotoValidator 中进行验证时,还有一些细节需要修改。
When the file is null , you need to add the precondition When(f => f.file != null)
to the statement that validates the Length and FileName fields, otherwise an error will occur:当文件为 null时,需要在验证Length 和 FileName字段的语句中添加前置条件When(f => f.file != null)
,否则会报错:
( Since you did not provide the relevant content of PhotoSettings
, I will set _settings.MaxBytes to a fixed value here ): (由于您没有提供PhotoSettings
的相关内容,我这里将 _settings.MaxBytes 设置为固定值):
public class PhotoValidator : AbstractValidator<FileData>
{
private readonly PhotoSettings _settings;
public PhotoValidator(/*PhotoSettings snapshot*/)
{
// _settings = snapshot;
_settings = new PhotoSettings() { MaxBytes = 2048000 };
RuleFor(f => f.file).NotNull().WithMessage("Please Attach your photo");
RuleFor(f => f.file.Length).ExclusiveBetween(0, _settings.MaxBytes)
.WithMessage($"File length should be greater than 0 and less than {_settings.MaxBytes / 1024 / 1024} MB")
.When(f => f.file != null);
RuleFor(f => f.file.FileName).Must(HaveSupportedFileType).When(f => f.file != null);
}
private bool HaveSupportedFileType(string fileName)
{
return _settings.IsSupported(fileName);
}
}
Here is the controller:这是 controller:
[HttpPost("{productId}")]
public IActionResult Upload([FromRoute]int productId, FileData data)
{
string errorMessages = null;
if (!ModelState.IsValid)
{
errorMessages = ModelState.Where(x => x.Value.ValidationState == ModelValidationState.Invalid).FirstOrDefault()
.Value.Errors.FirstOrDefault().ErrorMessage;
return Content(errorMessages);//return error message to show in view
}
return Ok();
}
View:看法:
@{
ViewData["Title"] = "Upload";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Upload</h1>
<form enctype="multipart/form-data" method="post">
<div class="form-group">
productId: <input name="productId" type="text" class="form-control" />
</div>
<div class="form-group">
<input type="file" name="file" /><br />
<span class="text-danger" id="fileMessage"></span>
</div>
<input id="Submit1" type="submit" value="submit" />
</form>
@section Scripts{
<script>
$("form").submit(function () {
event.preventDefault();
var productId = $("input[name=productId]").val();
var fd = new FormData();
var files = $('input[name=file]')[0].files[0];
fd.append('file', files);
var data = {
"file": fd,
};
$.ajax({
type: "post",
url: "/" + productId,
data: fd,
contentType: false,
processData: false,
dataType: "html",
success: function (message) {
$("#fileMessage").html(message);
if (message == "") {
alert("upload Success!");
}
}
})
})
</script>
}
Here is the test result:这是测试结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.