カスタム検証属性を記述し、カスタム クライアント側アダプターを登録できます。詳しく説明しましょう。
アップロードするファイルのリストを表すビュー モデルがあり、アップロードするすべてのファイルの合計サイズを 2 MB に制限したいとします。あなたのビューモデルは確かに次のように見えるかもしれません:
public class MyViewModel
{
[MaxFileSize(2 * 1024 * 1024, ErrorMessage = "The total file size should not exceed {0} bytes")]
public IEnumerable<HttpPostedFileBase> Files { get; set; }
}
[MaxFileSize]
ここで、明らかにサーバー側の検証を実行するこのカスタム検証属性を定義しましょうが、それに加えて、 IClientValidatableインターフェイスを実装して、この検証ロジックをクライアントに転置できるようにするカスタムの目立たないクライアント側検証ルールを登録できるようにします (明らかにHTML5 File APIをサポートするブラウザの場合、選択したファイルのサイズをクライアントで判断できます => IE は、このようなものやこのブラウザを使用するユーザーにとってはまったく問題外ですサーバー側のみの検証でそれらを満足させるか、何か良いことをする必要があります-この平和なソフトウェアが実行できるこの世界で唯一の有用なタスクにはInternet Explorerを使用します。Windowsをクリーンインストールしたら、インターネットを介して実際のファイルをダウンロードしますウェブブラウザ):
public class MaxFileSizeAttribute : ValidationAttribute, IClientValidatable
{
public MaxFileSizeAttribute(int maxTotalSize)
{
MaxTotalSize = maxTotalSize;
}
public int MaxTotalSize { get; private set; }
public override bool IsValid(object value)
{
var files = value as IEnumerable<HttpPostedFileBase>;
if (files != null)
{
var totalSize = files.Where(x => x != null).Sum(x => x.ContentLength);
return totalSize < MaxTotalSize;
}
return true;
}
public override string FormatErrorMessage(string name)
{
return base.FormatErrorMessage(MaxTotalSize.ToString());
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(MaxTotalSize.ToString()),
ValidationType = "maxsize"
};
rule.ValidationParameters["maxsize"] = MaxTotalSize;
yield return rule;
}
}
次のステップは、コントローラーを用意することです。
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (!ModelState.IsValid)
{
// Server side validation failed => redisplay the view so
// that the user can fix his errors
return View(model);
}
// Server side validation passed => here we can process the
// model.Files collection and do something useful with the
// uploaded files knowing that their total size will be smaller
// than what we have defined in the custom MaxFileSize attribute
// used on the view model
// ...
return Content("Thanks for uploading all those files");
}
}
および対応するビュー:
@model MyViewModel
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
(function ($) {
$.validator.unobtrusive.adapters.add('maxsize', ['maxsize'], function (options) {
options.rules['maxsize'] = options.params;
if (options.message) {
options.messages['maxsize'] = options.message;
}
});
$.validator.addMethod('maxsize', function (value, element, params) {
var maxSize = params.maxsize;
var $element = $(element);
var files = $element.closest('form').find(':file[name=' + $element.attr('name') + ']');
var totalFileSize = 0;
files.each(function () {
var file = $(this)[0].files[0];
if (file && file.size) {
totalFileSize += file.size;
}
});
return totalFileSize < maxSize;
}, '');
})(jQuery);
</script>
@Html.ValidationMessageFor(x => x.Files)
@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
@foreach (var item in Enumerable.Range(1, 3))
{
@Html.TextBoxFor(x => x.Files, new { type = "file" })
}
</div>
<button type="submit">OK</button>
}
明らかに、ここに示されている JavaScript は、ビュー内では何の関係もありません。ビューが参照できる別の再利用可能な JavaScript ファイルに入れる必要があります。ここでは、読みやすさとシナリオの再現を容易にするためにインラインで含めていますが、実際にはインライン JavaScript を記述することはありません。