使用自定义验证的 FileExtension Validation 创建重复和无效的 data-* 属性
Posted
技术标签:
【中文标题】使用自定义验证的 FileExtension Validation 创建重复和无效的 data-* 属性【英文标题】:FileExtension Validation using custom validation creates duplicate and invalid data-* attributes 【发布时间】:2016-01-30 14:47:57 【问题描述】:这个问题是在我尝试了 my previous question 中提到的答案之后提出的。我遵循 this article 完全相同的方式,但验证 image files
而不是文章中提到的 doc files
。
说明:我有一个input
控件type=file
,用于上传图像文件,这存在于partialview
之一中。 partialview
被加载到 click
的 button
上。要应用model
中提到的validations
,请将unobtrusive
显式添加到form
。但是按照上述文章中提到的所有设置后,我无法验证submit
上的文件,而且unobtrusive validation
创建的data-*
非常可疑,或者最好说无效。下面是显示我的设置的代码,这里是html
,它是由具有无效data-*
属性的不显眼验证创建的,可能是因为验证失败。
<input data-charset="file" data-val="true" data-val-fileextensions="" data-val-fileextensions-fileextensions="png,jpg,jpeg" id="File" multiple="multiple" name="File" type="file" value="">
加载部分视图 Js
$('.getpartial').on('click', function ()
$('.loadPartial').empty().load('/Home/GetView',function ()
var form = $('form#frmUploadImages');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
$(function ()
jQuery.validator.unobtrusive.adapters.add('fileextensions', ['fileextensions'], function (options)
var params =
fileextensions: options.params.fileextensions.split(',')
;
options.rules['fileextensions'] = params;
if (options.message)
options.messages['fileextensions'] = options.message;
);
jQuery.validator.addMethod("fileextensions", function (value, element, param)
var extension = getFileExtension(value);
var validExtension = $.inArray(extension, param.fileextensions) !== -1;
return validExtension;
);
function getFileExtension(fileName)
var extension = (/[.]/.exec(fileName)) ? /[^.]+$/.exec(fileName) : undefined;
if (extension != undefined)
return extension[0];
return extension;
;
(jQuery));
)
)
模型类
public class ImageUploadModel
[FileValidation("png|jpg|jpeg")]
public HttpPostedFileBase File get; set;
查看
@model ProjectName.Models.ImageUploadModel
@using (Html.BeginForm("UploadImages", "Admin", FormMethod.Post, htmlAttributes: new id = "frmUploadImages", novalidate = "novalidate", autocomplete = "off", enctype = "multipart/form-data" ))
<div class="form-group">
<span class="btn btn-default btn-file">
Browse @Html.TextBoxFor(m => m.File, new type = "file", multiple = "multiple", data_charset = "file" )
</span>
<span class="text-muted" id="filePlaceHolder">No files selected</span>
@Html.ValidationMessageFor(m => m.File, null, htmlAttributes: new @class = "invalid" )
</div>
<div class="form-group">
<button class="btn btn-primary addImage pull-right">
<i class="fa fa-upload"></i> Upload
</button>
</div>
最后是我的 CustomFileValidation 类
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FileValidationAttribute : ValidationAttribute, IClientValidatable
private List<string> ValidExtensions get; set;
public FileValidationAttribute(string fileExtensions)
ValidExtensions = fileExtensions.Split('|').ToList();
public override bool IsValid(object value)
HttpPostedFileBase file = value as HttpPostedFileBase;
if (file != null)
var fileName = file.FileName;
var isValidExtension = ValidExtensions.Any(y => fileName.EndsWith(y));
return isValidExtension;
return true;
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
var rule = new ModelClientFileExtensionValidationRule(ErrorMessage, ValidExtensions);
yield return rule;
public class ModelClientFileExtensionValidationRule : ModelClientValidationRule
public ModelClientFileExtensionValidationRule(string errorMessage, List<string> fileExtensions)
ErrorMessage = errorMessage;
ValidationType = "fileextensions";
ValidationParameters.Add("fileextensions", string.Join(",", fileExtensions));
【问题讨论】:
您的 2 个jQuery.validator
和 getFileExtension()
函数不应在 $('.getpartial').on('click', function ()
内 - 将它们移到方法之前(包括 $(function () .... (jQuery));
在内的所有内容)
此外,该代码只会验证一个文件,因此它可能不适用于multiple="multiple"
(尽管可以对其进行修改)
@StephenMuecke.. 太棒了.. 成功了.. 但是,data-*
属性,即data-val-fileextensions="" data-val-fileextensions-fileextensions="png,jpg,jpeg"
在DOM
中仍然保持不变。这不是invalid
吗?
data-val-fileextensions-fileextensions="png,jpg,jpeg"
的生成是因为 ModelClientFileExtensionValidationRule()
方法具有 ValidationType = "fileextensions";
和 `ValidationParameters.Add("fileextensions", ..)` - 这有点令人困惑,因为它们应该是不同的名称.而data-val-fileextensions=""
是因为你没有错误信息。
稍后我会添加一个答案,解释原因(以及multiple="multiple"
的潜在问题)
【参考方案1】:
你需要移动块代码
$(function ()
....
(jQuery));
从$('.getpartial').on(..)
函数内部到它之前,这样它就是
<script>
$(function ()
....
(jQuery));
$('.getpartial').on('click', function () // or just $('.getpartial').click(function()
$('.loadPartial').empty().load('/Home/GetView',function () // recommend .load('@Url.Action("GetView", "Home")', function()
var form = $('form#frmUploadImages');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
);
);
</script>
当前您加载内容,重新解析验证器,然后将方法添加到 jquery 验证中,但为时已晚(验证器已被解析)
旁注:您不需要将验证函数包装在$(function ()
中。它可以被删除,只需使用$.validator...
而不是jQuery.validator....
,就像您在代码的其他地方所做的那样。
至于“可疑”data-val-*
属性,这正是您的代码生成的。您生成一个名为fileextensions
的ClientValidationRule
(ValidationType = "fileextensions";
代码),然后添加它的一个属性,也称为fileextensions
(ValidationParameters.Add("fileextensions", ..)
代码生成data-val-fileextensions-fileextensions="png,jpg,jpeg"
。至于data-val-fileextensions=""
,即生成来存储错误消息,但您还没有生成一个,所以它是一个空字符串。
我建议对您的代码进行一些更改。
-
将其重命名为
FileTypeAttribute
,以便您可以灵活地
添加其他文件验证属性,例如
FileSizeAttribute
验证最大大小。
在构造函数中,生成默认错误信息,例如
添加private const string _DefaultErrorMessage = "Only the following file types are allowed: 0";
并在构造函数的最后一行包含ErrorMessage = string.Format(_DefaultErrorMessage, string.Join(" or ", ValidExtensions));
将ValidationParameters.Add("fileextensions", ...)
更改为(比如说)
ValidationParameters.Add("validtypes", ...)
所以它生成
data-val-fileextensions-validtypes="png,jpg,jpeg"
有点
更有意义(请注意,您需要将脚本更改为
...add('fileextensions', ['validtypes'], function() ....
编辑
您的代码不适用于 <input type="file" multiple="multiple" ... />
为此,您的属性需要为 IEnumerable
(请注意对您的代码进行一些小的更改)
[FileType("png, jpg, jpeg")]
public IEnumerable<HttpPostedFileBase> Files get; set;
那么validation属性需要检查集合中的每个文件
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FileTypeAttribute : ValidationAttribute, IClientValidatable
private const string _DefaultErrorMessage = "Only the following file types are allowed: 0";
private IEnumerable<string> _ValidTypes get; set;
public FileTypeAttribute(string validTypes)
_ValidTypes = validTypes.Split(',').Select(s => s.Trim().ToLower());
ErrorMessage = string.Format(_DefaultErrorMessage, string.Join(" or ", _ValidTypes));
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
IEnumerable<HttpPostedFileBase> files = value as IEnumerable<HttpPostedFileBase>;
if (files != null)
foreach(HttpPostedFileBase file in files)
if (file != null && !_ValidTypes.Any(e => file.FileName.EndsWith(e)))
return new ValidationResult(ErrorMessageString);
return ValidationResult.Success;
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
var rule = new ModelClientValidationRule
ValidationType = "filetype",
ErrorMessage = ErrorMessageString
;
rule.ValidationParameters.Add("validtypes", string.Join(",", _ValidTypes));
yield return rule;
最后脚本需要检查每个文件
$.validator.unobtrusive.adapters.add('filetype', ['validtypes'], function (options)
options.rules['filetype'] = validtypes: options.params.validtypes.split(',') ;
options.messages['filetype'] = options.message;
);
$.validator.addMethod("filetype", function (value, element, param)
for (var i = 0; i < element.files.length; i++)
var extension = getFileExtension(element.files[0].name);
if ($.inArray(extension, param.validtypes) === -1)
return false;
return true;
);
function getFileExtension(fileName)
if (/[.]/.exec(fileName))
return /[^.]+$/.exec(fileName)[0].toLowerCase();
return null;
【讨论】:
好的哥们.. 我明白.. 会做所有的改变和感谢FileSizeValidation
链接.. 你还说你会提到多文件上传处理.. 你能不能显示相同如果可能的话?
第一个问题是您的属性是HttpPostedFileBase
而不是IEnumerable<HttpPostedFileBase>
。然后是IsValid()
方法也基于一个文件(不是多个)并且脚本也在验证一个文件(不是循环遍历每个文件)的问题。没时间,但我明天会玩弄它,让你知道。
好的兄弟..非常感谢..我也会尽力解决..:)
查看更新(结合我之前提出的一些建议)
public IEnumerable<HttpPostedFileBase> Files get; set;
必须是您的ImageUploadModel
模型的属性(而不是您当前的public HttpPostedFileBase File get; set;
),然后在视图中使用@Html.TextBoxFor(m => m.Files, new type = "file", multiple = "multiple" )
以上是关于使用自定义验证的 FileExtension Validation 创建重复和无效的 data-* 属性的主要内容,如果未能解决你的问题,请参考以下文章