【问题标题】:MVC3 Custom Unobtrusive Validator on a List of Objects对象列表上的 MVC3 自定义不显眼验证器
【发布时间】:2012-06-10 16:39:11
【问题描述】:

开始的基本问题:如何将自定义的、不显眼的验证器放在模型中的对象列表之上?比如,假设我的模型允许上传多个文件,因此我有一个文件列表,我希望我的验证器在每个文件上运行?

现在举一个具体的例子。我有一个自定义的、不显眼的验证器,可以检查文件扩展名是否不在禁止扩展名列表中:

public class FileExtensionValidatorAttribute : ValidationAttribute, IClientValidatable {

    protected static string[] PROHIBITED_EXTENSIONS = {
        // ... List of extensions I don't allow.
    };

    public override bool IsValid(object value) {
        if (value is IEnumerable<HttpPostedFileBase>) {
            foreach (var file in (IEnumerable<HttpPostedFileBase>)value) {
                var fileName = file.FileName;
                if (PROHIBITED_EXTENSIONS.Any(x => fileName.EndsWith(x))) return false;
            }
        } else {
            var file = (HttpPostedFileBase)value;
            var fileName = file.FileName;
            if (PROHIBITED_EXTENSIONS.Any(x => fileName.EndsWith(x))) return false;
        }

        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
        var modelClientVlidationRule = new ModelClientValidationRule {
            ErrorMessage = this.ErrorMessageString,
            ValidationType = "fileextension",
        };
        modelClientVlidationRule.ValidationParameters.Add("prohibitedextensions", string.Join("|", PROHIBITED_EXTENSIONS));

        yield return modelClientVlidationRule;
    }
}

在我的 IsValid 中记下,我构建它是为了接受单个文件或文件列表。

在我的模型类中,我可以在单个 HttpPostedFileBase 上使用它:

[FileExtensionValidator(ErrorMessage = "Invalid Extension")]
public HttpPostedFileBase Upload { get; set; }

然后我在我的视图中附加到 jquery 的验证器:

jQuery.validator.addMethod("fileExtension", function (value, element, param) {
    var extension = "";
    var dotIndex = value.lastIndexOf('.');
    if (dotIndex != -1) extension = value.substring(dotIndex + 1).toLowerCase();

    return $.inArray(extension, param.prohibitedExtensions) === -1;
});

jQuery.validator.unobtrusive.adapters.add('fileextension', ['prohibitedextensions'], function (options) {
    options.rules['fileExtension'] = {
        prohibitedExtensions: options.params.prohibitedextensions.split('|')
    };
    options.messages['fileExtension'] = options.message;
});

这一切都很好,客户端和服务器端......但仅在单个 HttpPostedFileBase 上。问题是我需要为用户提供上传一个或多个文件的能力。如果我将模型更改为:

[FileExtensionValidator(ErrorMessage = "Invalid Extension")]
public List<HttpPostedFileBase> Uploads { get; set; }

...客户端验证不再运行;只有服务器端有效。这在查看源代码时很明显。生成的 标记缺少运行所需的所有 data-val 属性。在进行调试时,永远不会调用 GetClientValidationRules。

我错过了什么?

这可能是因为我如何渲染它吗?我只是为 HttpPostedFileBase 使用 EditorTemplate:

@model System.Web.HttpPostedFileBase
@Html.TextBoxFor(m => m, new { type = "file", size = 60 })

...我的观点是这样的:

<p>@Html.EditorFor(m => m.Uploads)</p>

感谢任何建议。

【问题讨论】:

  • 您的视图是否呈现多个文本框?上传后值在哪里/如何存储在客户端上?
  • 是的。多个文本框呈现正常,并且它们正在上传到服务器。 (服务器端验证确实在它们两个上都正确运行。)但是,对不起,我不明白你的第二个问题。
  • 你能上传几个文件并使用 DOM 检查器来显示渲染的 HTML 吗?
  • 如果您的意思是在将我上传的内容发回服务器后,我(还)没有意见;我确认服务器端验证仅通过调试器工作。如果您的意思是在我附加文件后但在上传之前检查 DOM,是的,我可以。我认为问题在于,在我附加之前,输入标签根本没有“data-val”属性。与所有其他经过客户端验证的字段一样。即,这是呈现的内容:。奇怪的是,jquery 正在向其中添加 class="valid",尽管我的 js 代码没有运行。
  • 验证器插件使用字段 name 来关联规则。您可能希望为 Assets[*] 命名字段创建自定义规则,或在提交表单时强制执行特定验证。

标签: asp.net-mvc asp.net-mvc-3 validation unobtrusive-validation


【解决方案1】:

这是我想出的。

我实际上认为问题最终是因为 MVC 不知道我希望将列表上的数据注释应用于其所有成员。我想也不应该。

所以我只是在 HttpPostedFileBase 周围制作了一个“viewmodel”包装器,并将我的验证器放在那里:

public class UploadedFile {
    [FileExtensionValidator(ErrorMessage = "Invalid Extension")]
    public HttpPostedFileBase File { get; set; }
}

然后,在我的实际模型中,我现在只使用这些列表:

public List<UploadedFile> Uploads { get; set; }

...这里当然没有更多的数据注释,因为它们现在在 UploadedFile 中。

然后,对视图和编辑器模板稍作修改以使用它们,现在可以正常工作,客户端和服务器端。 (不过,我觉得很笨拙。如果有人有更简单的方法,我仍然很高兴听到它。)

【讨论】:

    猜你喜欢
    • 2011-12-09
    • 2011-12-24
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多