我有一个强类型视图,它有一个DropDownListFor属性。
下拉列表中的每个项目都由GUID表示。
我所追求的是一种验证用户是否从下拉列表中选择项目的方法。目前我还没有看到使用数据注释做这件事。
无论如何使用数据注释实现此目的,因此客户端和服务器端验证将起作用。
我猜我需要制作一个自定义方法才能做到这一点,但想知道是否已存在任何事情。
答案 0 :(得分:19)
实际上,您不能将Required
属性与GUID一起使用(没有我在下面提到的方法),因为它们继承自struct
,因此它们的默认值实际上是Guid.Empty的一个实例,这将满足Required
属性的要求。现在有人说,有可能得到你想要的东西,只需要让你的财产可以为空,以此为例......
public class Person
{
[Required] //Only works because the Guid is nullable
public Guid? PersonId { get; set;}
public string FirstName { get; set;}
public string LastName { get; set;}
}
通过将GUID标记为可空(使用?或Nullable,如果您更喜欢漫长的方式),在绑定浏览器发送的内容时,让它保持为null。在您的情况下,只需确保下拉列表的默认选项的值使用空字符串作为其值。
编辑:此方法唯一需要注意的是,您最终必须在所有地方使用Person.GetValueOfDefault()
之类的内容,并可能会对Guid.Empty
进行测试。我厌倦了这样做,最终创建了自己的验证属性,以帮助简化验证Guids(以及任何其他具有我想要视为无效的默认值的类型,如int,DateTime等)。 但是我还没有客户端验证,所以验证只发生在服务器上。这可以与[Required]
结合使用(旨在不复制{{1}的功能1}})如果你可以使用可空类型。这意味着您仍然必须使用[Required]
,但至少您不必再测试GetValueOrDefault()
了。 Gist链接有一些带有示例的XMLDocs,为简洁起见,我将它们留在这里。我目前正在使用ASP.NET Core。
编辑已更新以修复Nullable<>的错误,以及将null视为无效的错误。添加了支持类来处理客户端验证。有关完整代码,请参阅Gist。
Guid.Empty
答案 1 :(得分:10)
已编辑的答案
重新阅读您的问题时,听起来您只想知道是否选择了某个值。如果是这种情况,那么只需将RequiredAttribute
应用于Guid
属性,并使其在模型上可为空
public class GuidModel
{
[Required]
public Guid? Guid { get; set; }
public IEnumerable<Guid> Guids { get; set; }
}
然后在强类型视图中(使用@model GuidModel
)
@Html.ValidationMessageFor(m => m.Guid)
@Html.DropDownListFor(
m => m.Guid,
Model.Guids.Select(g => new SelectListItem {Text = g.ToString(), Value = g.ToString()}),
"-- Select Guid --")
为客户端验证添加客户端验证JavaScript脚本引用。
控制器看起来像
public class GuidsController : Controller
{
public GuidRepository GuidRepo { get; private set; }
public GuidsController(GuidRepository guidRepo)
{
GuidRepo = guidRepo;
}
[HttpGet]
public ActionResult Edit(int id)
{
var guid = GuidRepo.GetForId(id);
var guids - GuidRepo.All();
return View(new GuidModel { Guid = guid, Guids = guids });
}
[HttpPost]
public ActionResult Edit(GuidModel model)
{
if (!ModelState.IsValid)
{
model.Guids = GuidRepo.All();
return View(model);
}
/* update db */
return RedirectToAction("Edit");
}
}
这将确保模型绑定Guid
需要GuidModel
属性。
原始答案
我不相信有一个现成的Data Annotation Validation属性能够做到这一点。我写了a blog post about one way to achieve this;帖子使用的是IoC容器,但是如果你想让某些东西工作,你可以采用硬编码的依赖。
像
这样的东西public class ValidGuidAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "'{0}' does not contain a valid guid";
public ValidGuidAttribute() : base(DefaultErrorMessage)
{
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var input = Convert.ToString(value, CultureInfo.CurrentCulture);
// let the Required attribute take care of this validation
if (string.IsNullOrWhiteSpace(input))
{
return null;
}
// get all of your guids (assume a repo is being used)
var guids = new GuidRepository().AllGuids();
Guid guid;
if (!Guid.TryParse(input, out guid))
{
// not a validstring representation of a guid
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
// is the passed guid one we know about?
return guids.Any(g => g == guid) ?
new ValidationResult(FormatErrorMessage(validationContext.DisplayName)) : null;
}
}
然后在您发送到控制器操作的模型上
public class GuidModel
{
[ValidGuid]
public Guid guid { get; set; }
}
这为您提供服务器端验证。您可以编写客户端验证来执行此操作,也许使用RemoteAttribute
但在这种情况下我没有看到很多价值,因为唯一会看到此客户端验证的人是那些搞乱的人与DOM中的值;这对普通用户没有任何好处。
答案 2 :(得分:3)
我知道这是一个古老的问题,但是如果有其他人感兴趣的话,我设法通过创建一个[IsNotEmpty]注释来解决这个问题(在我的情况下,使Guid可以作为一个选项)。
这使用反射来计算属性上是否有Empty的实现,如果有,则比较它。
public class IsNotEmptyAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null) return false;
var valueType = value.GetType();
var emptyField = valueType.GetField("Empty");
if (emptyField == null) return true;
var emptyValue = emptyField.GetValue(null);
return !value.Equals(emptyValue);
}
}
答案 3 :(得分:2)
正则表达式实际上可以正常工作(如果您使用的是正确的!)
[Required]
[RegularExpression("^((?!00000000-0000-0000-0000-000000000000).)*$", ErrorMessage = "Cannot use default Guid")]
public Guid Id { get; set; }
答案 4 :(得分:1)
非空Guid验证器
防止00000000-0000-0000-0000-000000000000
属性:
using System.ComponentModel.DataAnnotations; [AttributeUsage(AttributeTargets.Property)] internal class NonEmptyGuidAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if ((value is Guid) && Guid.Empty == (Guid)value) { return new ValidationResult("Guid cannot be empty."); } return null; } }
型号:
using System.ComponentModel.DataAnnotations;
public class Material
{
[Required]
[NonEmptyGuid]
public Guid Guid { get; set; }
}
答案 5 :(得分:1)
您可以验证Guid是否包含默认值-“ 00000000-0000-0000-0000-000000000000”。
if (model.Id == Guid.Empty)
{
// TODO: handle the error or do something else
}
答案 6 :(得分:0)
如果自定义验证不需要在系统中高度重复使用(即不需要自定义验证属性),则可以使用另一种方法将自定义验证添加到ViewModel / Posted数据模型,即使用{{3 }}。
每个错误都可以绑定到一个或多个模型属性,因此该方法仍然适用于例如在MVC Razor中进行不显眼的验证。
以下是检查Guid默认设置(C#7.1)的方法:
public class MyModel : IValidatableObject // Implement IValidatableObject
{
[Required]
public string Name {get; set;}
public Guid SomeGuid {get; set;}
... other properties here
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (SomeGuid == default)
{
yield return new ValidationResult(
"SomeGuid must be provided",
new[] { nameof(SomeGuid) });
}
}
}
有关IValidatableObject的更多信息
答案 7 :(得分:0)
错误答案。见下文...
使用正则表达式阻止空白/默认Guid为我工作。与“必需”组合使用。即
[Required]
[RegularExpression("^(?!(00000000-0000-0000-0000-000000000000)$)", ErrorMessage = "Cannot use default Guid")]
public Guid Id { get; set; }
编辑:实际上这是行不通的。它拒绝一切。 我将保留此答案,以免其他人麻烦尝试。