【问题标题】:Best practice entity validation in ASP.NET MVC & ADO.NET Entity FrameworkASP.NET MVC 和 ADO.NET 实体框架中的最佳实践实体验证
【发布时间】:2010-11-11 15:23:51
【问题描述】:

我在一个项目中使用 ASP.NET MVC 和 ADO.NET 实体框架。我想通过部分类向我的实体添加验证逻辑。它的工作方式类似于使用 LINQ2SQL 的NerdDinner.com ASP.NET MVC Application 中所示。主要区别在于,我必须使用“OnPropertyChanging”事件而不是 LINQ2SQL 中的“OnValidating”。

这样做有一些问题: - “OnPropertyChanging”事件不是调用验证逻辑的最佳点,因为它总是触发,即使在创建调用默认构造函数时也是如此。这确实会导致严重的问题(不仅仅是性能问题)。 - 与 MVC 框架一起使用“EntityState.Detached”(我找不到任何其他方式)来确定是否需要验证实体时存在问题。因为实体在视图中显示期间会丢失其实体状态(因为在 POST 事件中会创建一个新实体对象而不是返回原始实体对象)。

我的问题是:有没有更好的方法向 ADO.NET 实体添加验证?我找不到任何使用向 ADO.NET 实体添加验证的实用方法的教程。

【问题讨论】:

    标签: .net asp.net-mvc entity-framework validation


    【解决方案1】:

    就我个人而言,我不会在对象本身中进行验证。我使用xVal 库来处理我的实体验证。

    xVal 鼓励您使用描述各种验证规则的属性来注释您的实体类(或者实际上是元数据伴随类)。这些验证属性是 .NET System.ComponentModel.DataAnnotations 中的默认属性。

    然后,您可以在业务层中手动对对象运行验证。这是通过使用运行 System.ComponentModel.DataAnnotations 验证逻辑的方法来完成的。我写了一个看起来像这样的:

    /// <summary>
    /// Gets the validation errors for the passed in object by using reflection to retrieve the 
    /// <see cref="ValidationAttribute"/>s placed on its properties or on the properties of the object's
    /// metadata class (as specified by a <see cref="MetadataTypeAttribute"/> placed on the object's class)
    /// </summary>
    /// <param name="instance">The object to validate</param>
    /// <returns>Any validation errors</returns>
    /// <remarks>
    /// Borrowed (and cleaned up) from
    /// http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/
    /// </remarks>
    public static IEnumerable<ErrorInfo> Validate(object instance)
    {
        //Try to get the MetadataType attribute from the object
        MetadataTypeAttribute metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();
    
        //If the MetadataType attribute existed, get the metadata class
        //else just use the class of the object
        Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();
    
        IEnumerable<PropertyDescriptor> buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
        IEnumerable<PropertyDescriptor> modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();
    
        //This query matches each property on the model class against the buddy class
        //gets a list of all invalid validation attributes and returns a list of
        //validation errors
        return from buddyProp in buddyClassProperties
               join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
               from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
               where !attribute.IsValid(modelProp.GetValue(instance))
               select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(String.Empty), instance);
    }
    

    xVal 提供了一种简洁的异常类型,您可以抛出它,它封装了验证错误,并允许您轻松地将它们添加到 Controller 中的 ModelState。

    xVal 还将通过提供 HtmlHelper 方法利用 jQuery.Validate 为您自动生成客户端 JavaScript 表单验证代码。

    查看http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ 了解其工作原理。我发现它是一种非常好的验证方式,而不是一件苦差事。它非常适合 ASP.NET MVC 的处理方式。

    【讨论】:

    • 值得注意的是,这是在 MVC v1 中获得注解验证所必需的。由于内置了MVC v2数据注解验证,所以不需要xVal。
    【解决方案2】:

    就个人而言,我不使用OnXChanging 部分。对于为该方法签名执行某些操作的实体,您必须拥有另一个分部类。

    我有一个集中保存(通过该实体的辅助方法,或该实体的存储库模式实现的保存),在执行我的context.SaveChanges() 之前,我在其中验证值是否符合我的标准。

    我也不会使用 onpropertychanging 事件进行验证,如果我有一个集中保存,那么我只需要在一个地方进行验证,我会将其留给其他点的特定触发器。 (就像如果用户更改了 X 然后更新 Y)

    【讨论】:

    • OnXChangeing 不是您说对的事件。但 OnPropertyChanging 是一个事件。
    • 是的 OnPropertyChanged 是一个不错的中心事件。但是你仍然有很多次不必要的帽子验证触发问题。 EventState.Detached 不适用于 ASP.NET MVC,因为它会丢失...这就是 Web 应用程序“无状态”的原因 :-)
    • 是的,这就是为什么我会使用某种存储库模式来很好地分离到业务对象/重新附加到 EF
    【解决方案3】:

    验证 EF 实体对象的一种简单方法是在模型类上使用 DataAnnotations。这种方法有两个明显的好处。一是相同的验证逻辑可以在许多视图中重用,例如编辑和创建。另一个是当我们的实体类中可以使用数据注释时,ASP.NET MVC 提供了开箱即用的客户端和服务器端验证,而无需太多固定装置和编码。

    http://theminimalistdeveloper.com/2010/07/23/how-to-do-client-side-validation-in-asp-net-mvc-2/ 以简单的步骤展示了如何在 EF 4.0 中实现这一目标

    【讨论】:

      【解决方案4】:

      您是否研究过 IValidatableObject 实现。我不确定这是否能回答您的问题;但是,这样您的验证将保留在您的域对象中。

      更多关于它的例子是: How do I use IValidatableObject?

      DataAnnotations 用于运行正常的验证;但是,如果有复杂的验证,您可以创建自己的 ValidationAttribute 或实现 IValidatableObject。如果你走这条路,你可以使用两者的组合。我一般都是这样做的。

      【讨论】:

      • 这适用于 DataAnnoations。此外,如果有任何 DataAnnotations 验证错误,框架短路并且不会调用 Validate 方法。
      猜你喜欢
      • 2010-09-14
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多