Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Guid的验证_C#_Asp.net Mvc_Data Annotations_Guid - Fatal编程技术网

C# Guid的验证

C# Guid的验证,c#,asp.net-mvc,data-annotations,guid,C#,Asp.net Mvc,Data Annotations,Guid,我有一个强类型视图,它有一个DropDownListFor属性 下拉列表中的每个项目都由GUID表示 我想要的是一种验证用户是否从下拉列表中选择某个项目的方法。目前,我看不到使用数据注释来实现这一点 是否有任何方法可以使用数据注释来实现这一点,这样客户端和服务器端验证就可以工作了 我猜我需要定制一个方法来实现这一点,但我想知道是否已经存在任何东西。编辑的答案 重新阅读您的问题后,听起来您只是想知道是否选择了某个值。如果是这种情况,那么只需将 public class GuidModel {

我有一个强类型视图,它有一个DropDownListFor属性

下拉列表中的每个项目都由GUID表示

我想要的是一种验证用户是否从下拉列表中选择某个项目的方法。目前,我看不到使用数据注释来实现这一点

是否有任何方法可以使用数据注释来实现这一点,这样客户端和服务器端验证就可以工作了


我猜我需要定制一个方法来实现这一点,但我想知道是否已经存在任何东西。

编辑的答案

重新阅读您的问题后,听起来您只是想知道是否选择了某个值。如果是这种情况,那么只需将

public class GuidModel
{
    [Required]
    public Guid? Guid { get; set; }

    public IEnumerable<Guid> Guids { get; set; }
}
为客户端验证添加客户端验证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");
    }
}
这将确保模型绑定的
GuidModel
需要
Guid
属性

原始答案

我不相信有现成的数据注释验证属性能够做到这一点。我写;这篇文章使用的是一个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; }
}

这将为您提供服务器端验证。您也可以编写客户端验证来实现这一点,也许可以使用,但在这种情况下,我看不出有多大价值,因为只有那些正在处理DOM中的值的人才会看到客户端验证;这对您的普通用户没有任何好处。

实际上,您不能将
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(使用?或nullable,如果您愿意的话),可以在绑定浏览器发送的内容时使其保持为null。在您的情况下,只需确保下拉列表的默认选项的值使用空字符串作为其值

EDIT:此方法的唯一警告是,您最终必须在任何地方使用类似于
Person.GetValueOfDefault()的东西,并可能测试
Guid.Empty
。我厌倦了这样做,最终创建了自己的验证属性来帮助简化验证guid(以及任何其他具有默认值的类型,如int、DateTime等,我希望将其视为无效)。但是,我还没有进行客户端验证,因此验证只在服务器上进行。如果您同意使用可空类型,则可以将其与
[必需]
(设计为不复制
[必需]
的功能)结合使用。这意味着您仍然必须使用
GetValueOrDefault()
,但至少不必再测试
Guid.Empty
。Gist链接中有一些带有示例的XMLDocs,为了简洁起见,我把它们放在这里了。我目前正在使用它与ASP.NET核心

编辑:更新以修复可为null的错误,以及将null视为无效的错误。添加了支持类来处理客户端验证。完整代码见要点

要点:


我知道这是一个老问题,但是如果其他人感兴趣,我通过创建一个[IsNotEmpty]注释来解决这个问题(在我的例子中,使Guid为null不是一个选项)

这使用反射来确定属性上是否有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);

    }
}

如果自定义验证不需要在系统中高度重用(即不需要自定义验证属性),则有另一种方法可以将自定义验证添加到ViewModel/Posted数据模型,即使用

每个错误都可以绑定到一个或多个模型属性,因此这种方法仍然适用于MVC Razor中的不引人注目的验证

下面是如何检查Guid的默认值(C#7.1):

公共类MyModel:IValidatableObject//实现IValidatableObject
{
[必需]
公共字符串名称{get;set;}
公共Guid SomeGuid{get;set;}
……这里还有其他房产
公共IEnumerable验证(ValidationContext ValidationContext)
{
if(SomeGuid==默认值)
{
返回新的ValidationResult(
“必须提供SomeGuid”,
新[]{nameof(SomeGuid)};
}
}
}

有关非空Guid验证程序的详细信息

阻止00000000-0000-0000-0000-000000000000

属性:

型号:

using System.ComponentModel.DataAnnotations;
public class Material
{
    [Required]
    [NonEmptyGuid]
    public Guid Guid { get; set; }
}
正则表达式确实有效(如果使用正确的正则表达式!)


如果Guid包含默认值——“00000000-0000-0000-0000-0000-000000000000”,则可以验证Guid


除非您将Guid属性标记为可空,否则这实际上是行不通的,请参见我的答案。我尝试在模型中使用您的代码和下面的属性,如果我提供空值,模型将失败?根据总结中的示例,我认为null是可以的,但在本例中不是0。请确认[RequiredNonfault]公共整数?测试{get;set;}这是因为您的类型是
int?。并且任何
Nullable`对象的默认值都为null,因此null无效,但0无效。然而你是对的,我的例子暗示了另一种情况。我会解决的。为了让您所描述的工作正常(允许null,但不允许0),您最好使用这样的
[Range(1,int.MaxValue)]int?i{get;set;}
@Albercht感谢您的确认。为什么上面的另一位作者声明此解决方案无效?他/她的正则表达式
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);

    }
}
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) });
        }
    }
 }
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; }
}
[Required]
[RegularExpression("^((?!00000000-0000-0000-0000-000000000000).)*$", ErrorMessage = "Cannot use default Guid")]
public Guid Id { get; set; }
  if (model.Id == Guid.Empty)
  {
           // TODO: handle the error or do something else
  }