4

開始する基本的な質問:モデル内のオブジェクトのリストの上に、目立たないカスタムバリデーターをどのように配置できますか?たとえば、私のモデルでは複数のファイルのアップロードが許可されているため、ファイルのリストがあり、それらの各ファイルでバリデーターを実行したいとしますか?

次に、具体的な例を示します。ファイル拡張子が禁止されている拡張子のリストに含まれていないかどうかを確認する、目立たないカスタムバリデーターがあります。

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でのみ機能します。問題は、ユーザーに1つ以上のファイルをアップロードする機能を提供する必要があることです。モデルをこれに変更した場合:

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

...クライアント側の検証は実行されなくなりました。サーバー側のみが機能します。これは、ビューソースを実行するときに明らかです。生成される<input>タグには、実行する必要のあるすべての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>

アドバイスをいただければ幸いです。

4

1 に答える 1

3

これが私が思いついたものです。

実際、この問題は最終的には、リスト上のデータ注釈をすべてのメンバーに適用することをMVCが認識していないために発生していると思います。また、私が推測するべきではありません。

そこで、HttpPostedFileBaseの周りに「viewmodel」ラッパーを作成し、そこにバリデーターを配置しました。

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

次に、実際のモデルでは、代わりにそれらのリストを使用します。

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

...もちろん、UploadedFileにあるので、ここにはこれ以上のデータ注釈はありません。

次に、これらを使用するためにビューとeditortemplateに小さな変更を加えることで、これはクライアント側とサーバー側で正常に機能するようになりました。(それでも、私には不格好な感じがします。誰かがもっと簡単な方法を持っているなら、私はそれを聞いて幸せです。)

于 2012-06-06T20:00:04.120 に答える