有时候,我们希望2个属性中,至少有一个是必填,比如:
using Car.Test.Portal.Extension;
namespace Car.Test.Portal.Models
{
public class Person
{
public int Id { get; set; }
public string Telephone { get; set; }
public string Address { get; set; }
}
}
如果让Telephone和Address属性中,有一个是必填项,需要自定义特性。
□ 自定义AtLeastOneAttribute特性,派生于ValidationAttribute类,并实现IClientValidatable接口
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
namespace Car.Test.Portal.Extension
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class AtLeastOneAttribute : ValidationAttribute, IClientValidatable
{
public string PrimaryProperty { get; private set; }
public string SecondaryProperty { get; private set; }
public AtLeastOneAttribute(string primaryProperty, string secondProperty)
{
PrimaryProperty = primaryProperty;
SecondaryProperty = secondProperty;
}
public override string FormatErrorMessage(string name)
{
return string.Format(CultureInfo.CurrentCulture, this.ErrorMessageString, PrimaryProperty, SecondaryProperty);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object primaryValue = properties.Find(PrimaryProperty, true /* ignoreCase */).GetValue(value);
object secondaryValue = properties.Find(SecondaryProperty, true /* ignoreCase */).GetValue(value);
if (primaryValue != null || secondaryValue != null)
{
return true;
}
else
{
return false;
}
//return (primaryValue != null || secondaryValue != null);
//稍稍改动以下还可以比较2个属性是否相等
//if (!primaryValue.Equals(secondaryValue))
// return true;
//else
// return false;
}
public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
string errorMessage = FormatErrorMessage("");
ModelClientValidationRule rule = new ModelClientValidationRule()
{
ValidationType = "atleastone",
ErrorMessage = errorMessage
};
rule.ValidationParameters.Add("primary", this.PrimaryProperty);
rule.ValidationParameters.Add("secondary", this.SecondaryProperty);
yield return rule;
}
}
}
□ 把自定义特性AtLeastOneAttribute打到类上
using Car.Test.Portal.Extension;
namespace Car.Test.Portal.Models
{
[AtLeastOne("Telephone", "Address",ErrorMessage = "Telephone和Address至少填一项~~")]
public class Person
{
public int Id { get; set; }
public string Telephone { get; set; }
public string Address { get; set; }
}
}
□ PersonController
public class PersonController : Controller
{
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Person person)
{
if (ModelState.IsValid)
{
//TODO:
return Content("ok");
}
else
{
return View(person);
}
}
}
□ Person/Index.cshtml
需要把自定义的特性注册到jquery相关类库中。
@model Car.Test.Portal.Models.Person
<body>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery-migrate-1.2.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
@*<script src="~/Scripts/atleastone.js"></script>*@
<style type="text/css">
.validation-summary-errors {
color: red;
}
</style>
<script type="text/javascript">
jQuery.validator.addMethod("atleastone", function (value, element, params) {
var primaryProperty = params.primary;
var secondaryProperty = params.secondary;
if (primaryProperty.length > 0 || secondaryProperty.length > 0) {
return true;
} else {
return false;
}
});
jQuery.validator.unobtrusive.adapters.add("atleastone", ["primary", "secondary"], function (options) {
options.rules["atleastone"] = {
primary: options.params.primary,
secondary: options.params.secondary
};
options.messages["atleastone"] = options.message;
});
</script>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Telephone)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Telephone)
@Html.ValidationMessageFor(model => model.Telephone)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Address)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Address)
@Html.ValidationMessageFor(model => model.Address)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
</body>
</html>
□ 效果