Ответ 1
Общий дизайн
Для начала, я считаю, что вам нужно будет как-то отслеживать, если пользователь решит игнорировать предупреждения. Простой и прозрачный способ сделать это - установить флажок Ignore Warnings, который пользователь должен будет проверить перед отправкой. Другим вариантом является то, что они должны отправить форму два раза и игнорировать предупреждения на второй submit; то вам, вероятно, понадобится скрытое поле IgnoreWarnings. Могут быть другие конструкции, но для простоты я пошлю первый вариант.
Короче говоря, подход заключается в создании
- Пользовательский атрибут аннотации данных для всех моделей просмотров, поддерживающих тип проверки предупреждения;
- Известный базовый класс, который наследует модели вида:
- Нам придется дублировать логику JavaScript для каждого настраиваемого атрибута.
Обратите внимание, что приведенный ниже код просто иллюстрирует подход, и я должен принять множество вещей, не зная полного контекста.
Показать модель
В этом сценарии лучше всего отделить модель представления от реальной модели, которая в любом случае является хорошей идеей. Один из возможных подходов состоит в том, чтобы иметь базовый класс для всех моделей представлений, которые поддерживают предупреждения:
public abstract class BaseViewModel
{
public bool IgnoreWarnings { get; set; }
}
Основная причина, по которой модель должна быть отдельной, заключается в том, что нет никакого смысла хранить свойство IgnoreWarnings
в вашей базе данных.
Ваша производная модель просмотра будет выглядеть следующим образом:
public class YourViewModel : BaseViewModel
{
[Required]
[StringLengthWarning(MaximumLength = 5, ErrorMessage = "Your Warning Message")]
public string YourProperty { get; set; }
}
StringLengthWarning
- это специальный атрибут аннотации данных для проверки на стороне сервера и на стороне клиента. Он просто поддерживает максимальную длину и может быть легко расширен с любыми другими необходимыми свойствами.
Атрибут аннотации данных
Ядром атрибута является IsValid(value, validationContext
метод.
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class StringLengthWarningAttribute : ValidationAttribute, IClientValidatable
{
public int MaximumLength { get; set; }
public override bool IsValid(object value)
{
return true;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var model = validationContext.ObjectInstance as BaseViewModel;
var str = value as string;
if (!model.IgnoreWarnings && (string.IsNullOrWhiteSpace(str) || str.Length > MaximumLength))
return new ValidationResult(ErrorMessage);
return base.IsValid(value, validationContext);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new StringLengthWarningValidationRule(MaximumLength, ErrorMessage);
}
}
Атрибут реализует IClientValidatable
и использует правило проверки клиента:
public class StringLengthWarningValidationRule : ModelClientValidationRule
{
public StringLengthWarningValidationRule(int maximumLength, string errorMessage)
{
ErrorMessage = errorMessage;
ValidationType = "stringlengthwarning";
ValidationParameters.Add("maximumlength", maximumLength);
ValidationParameters.Add("ignorewarningsfield", "IgnoreWarnings");
}
}
Клиентский JavaScript
Наконец, чтобы заставить его работать, вам понадобится следующий JavaScript, указанный в вашем представлении:
$(function () {
$.validator.addMethod('stringlengthwarning', function (value, element, params) {
var maximumlength = params['maximumlength'];
var ignorewarningsfield = params['ignorewarningsfield'];
var ctl = $("#" + ignorewarningsfield);
if (ctl == null || ctl.is(':checked'))
return true;
return value.length <= maximumlength;
});
$.validator.unobtrusive.adapters.add("stringlengthwarning", ["maximumlength", "ignorewarningsfield"], function (options) {
var value = {
maximumlength: options.params.maximumlength,
ignorewarningsfield: options.params.ignorewarningsfield
};
options.rules["stringlengthwarning"] = value;
if (options.message) {
options.messages["stringlengthwarning"] = options.message;
}
});
}(jQuery));
JavaScript делает некоторые предположения, которые вы, возможно, захотите пересмотреть (имя check-box и т.д.).
ОБНОВЛЕНИЕ: HTML-помощники
Чтобы отображать сообщения проверки отдельно для ошибок и предупреждений, потребуется несколько помощников. Следующий класс предоставляет образец:
public static class MessageHelpers
{
public static MvcHtmlString WarningMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] != null)
return htmlHelper.ValidationMessageFor(expression);
return MvcHtmlString.Empty;
}
public static MvcHtmlString ErrorMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] == null)
return htmlHelper.ValidationMessageFor(expression);
return MvcHtmlString.Empty;
}
}
В представлении они могут использоваться как обычно:
@Html.EditorFor(model => model.YourProperty)
@Html.ErrorMessageFor(model => model.YourProperty)
@Html.WarningMessageFor(model => model.YourProperty)