Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.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# 在层之间同步验证值_C#_Asp.net_Validation - Fatal编程技术网

C# 在层之间同步验证值

C# 在层之间同步验证值,c#,asp.net,validation,C#,Asp.net,Validation,我有一个关于层间数据验证的问题。例如,假设我有一个名为Book的对象,其字符串属性名为Title 在数据库中,我有一个特定的Title长度,它将指示我可以在Title属性中存储多少个字符 我正在验证应用程序中每个层之间的请求。因此,我在表示层验证用户输入,验证对我的应用层的服务调用,SQL数据库显然会在我尝试插入数据之前验证数据 我的问题是,如果我对Title属性的长度有限,那么通过每一层进行沟通的最佳方式是什么。如果SQL Server说长度不能超过40个字符,那么告诉其他层这一点的最佳方法是

我有一个关于层间数据验证的问题。例如,假设我有一个名为Book的对象,其字符串属性名为Title

在数据库中,我有一个特定的Title长度,它将指示我可以在Title属性中存储多少个字符

我正在验证应用程序中每个层之间的请求。因此,我在表示层验证用户输入,验证对我的应用层的服务调用,SQL数据库显然会在我尝试插入数据之前验证数据

我的问题是,如果我对Title属性的长度有限,那么通过每一层进行沟通的最佳方式是什么。如果SQL Server说长度不能超过40个字符,那么告诉其他层这一点的最佳方法是什么,而不必将长度值硬编码到每个层中

在这种情况下你们会怎么做?

首先:

SQL数据库显然会在我尝试之前验证数据 插入它

不,不会的。如果您通过参数传递,它将被截断。如果您运行的是直接sql语句,则在运行insert后将收到一个错误

也就是说,我们通过属性向对象添加验证器,并在尝试将数据传递到db服务器之前启动企业库验证。这使我们能够以多种语言自定义每个属性的消息

例如:

上面的类是使用企业库验证器的一个非常简单的示例。主要需要注意的是AccountNumber属性上的属性,该属性基本上表示帐号必须包含1到50个字符

我们将Validate方法放在一个基类中,每当我们要持久化数据时就会调用该基类。此外,我们的validate方法实际上返回了一组错误,我们将这些错误过滤到试图保存对象的任何内容。接下来,我们使用控制反转模式将适当的数据层接口传递给对象本身。同样,通过这种方式,我们可以将对象保存逻辑保存在其自身中,同时仍然支持模拟功能以及随意交换持久性机制(即:数据库服务器)的能力。这在上面的代码示例中没有表示

从本质上讲,这允许我们将验证逻辑保留在业务类中,而其他每一层都可以忽略它,只需将任何错误过滤到屏幕上的适当位置(通常是消息区域)。如果您有专门的验证逻辑,那么添加自定义验证器并将属性分散到需要它们的地方是非常简单的

最后一点是,每个层都可以随时调用validate方法,而不仅仅是在save操作期间,以确保数据一致性

首先:

SQL数据库显然会在我尝试之前验证数据 插入它

不,不会的。如果您通过参数传递,它将被截断。如果您运行的是直接sql语句,则在运行insert后将收到一个错误

也就是说,我们通过属性向对象添加验证器,并在尝试将数据传递到db服务器之前启动企业库验证。这使我们能够以多种语言自定义每个属性的消息

例如:

上面的类是使用企业库验证器的一个非常简单的示例。主要需要注意的是AccountNumber属性上的属性,该属性基本上表示帐号必须包含1到50个字符

我们将Validate方法放在一个基类中,每当我们要持久化数据时就会调用该基类。此外,我们的validate方法实际上返回了一组错误,我们将这些错误过滤到试图保存对象的任何内容。接下来,我们使用控制反转模式将适当的数据层接口传递给对象本身。同样,通过这种方式,我们可以将对象保存逻辑保存在其自身中,同时仍然支持模拟功能以及随意交换持久性机制(即:数据库服务器)的能力。这在上面的代码示例中没有表示

从本质上讲,这允许我们将验证逻辑保留在业务类中,而其他每一层都可以忽略它,只需将任何错误过滤到屏幕上的适当位置(通常是消息区域)。如果您有专门的验证逻辑,那么添加自定义验证器并将属性分散到需要它们的地方是非常简单的


最后一点是,每个层都可以随时调用validate方法,而不仅仅是在save操作期间,以确保数据一致性

我希望有一种机制,允许我在访问数据库之前验证实体。在UI和业务层中

为什么?

数据库通常不会 我不能容忍任何违反已定义模式的行为,它们通常会抛出异常,这非常糟糕,特别是当您使用诸如NHibernate或Entity framework之类的持久性框架时。这些框架通常使用工作单元模式,并尝试一次性完成所有工作,如果出现问题,则无法保证您能够做到再拍一次:

怎么做

在大多数解决方案中,这意味着元数据xml配置文件或.net属性 这意味着使这些元数据与数据库同步。MVC框架有这样一种开箱即用的机制,在我看来这很酷 我从未见过这种元数据解决方案的替代方案,但也许我们可以使用数据库的实际模式动态构建元数据

警告用户这些违规行为的策略可能有所不同。
有些人喜欢在出现错误时立即通知用户FieldValidate by Field,有些人喜欢在用户提供所有数据后通知用户validate by form,但有一点很清楚:在这两种情况下,都应该有一个单一的基础结构负责验证模型,并且该基础结构应该独立于模型,因此可以重复使用

我希望有一种机制,允许我在访问数据库之前验证实体。在UI和业务层中

为什么?

数据库通常不会容忍任何违反已定义模式的行为,它们通常会抛出异常,这非常糟糕,特别是当您使用诸如NHibernate或Entity framework之类的持久性框架时。这些框架通常使用工作单元模式,尝试一次完成所有工作,如果出现问题不能保证你能再拍一次:

怎么做

在大多数解决方案中,这意味着元数据xml配置文件或.net属性 这意味着使这些元数据与数据库同步。MVC框架有这样一种开箱即用的机制,在我看来这很酷 我从未见过这种元数据解决方案的替代方案,但也许我们可以使用数据库的实际模式动态构建元数据

警告用户这些违规行为的策略可能有所不同。
有些人喜欢在出现错误时立即通知用户FieldValidate by Field,有些人喜欢在用户提供所有数据后通知用户validate by form,但有一点很清楚:在这两种情况下,都应该有一个单一的基础结构负责验证模型,并且该基础结构应该独立于模型,因此可以重复使用

我不认为有现成的解决方案可以完全实现您的域验证与数据库的连接

但是有了一些智能,我们可以实现一些可以为您节省大量额外工作的东西

我建议您考虑使用以下框架

这将允许您创建一个验证类,您可以使用该类在整个应用程序层中验证域模型

因此,每个模型只需要一个验证类,然后DB当然会让您知道该级别的任何问题

或者,如果需要,您可以为每个层、每个场景或您想要的任何方式创建一个验证类

请看下面CodePlex中的一些实现代码:

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Company).NotNull();
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> 

failures = results.Errors;

我不认为有一个现成的解决方案可以完全实现您的域验证与数据库的连接

但是有了一些智能,我们可以实现一些可以为您节省大量额外工作的东西

我建议您考虑使用以下框架

这将允许您创建一个验证类,您可以使用该类在整个应用程序层中验证域模型

因此,每个模型只需要一个验证类,然后DB当然会让您知道该级别的任何问题

或者,如果需要,您可以为每个层、每个场景或您想要的任何方式创建一个验证类

请看下面CodePlex中的一些实现代码:

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Company).NotNull();
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> 

failures = results.Errors;

好的,那个么如何处理诸如max length之类的值呢?如果数据库中字段的最大长度为10,是否将值10硬编码到层中?还是使用中心配置?@ChrisPaynter:10被烘焙到类定义中。所有的层都依赖于对象来确定它是否有效。啊,非常感谢。所以我猜你是在用一个public const int吗?@chrislive你能举个例子来支持你的答案吗?我的意思是更新您的答案,其中包含一个示例,说明其他层如何依赖于您为其设置属性的对象。这将更加清晰…@ChrisPaynter:不。请看更新。我认为代码示例将更有意义。好的,那么您如何处理最大长度等值?如果数据库中某个字段的最大长度为10,是否将值10硬编码到数据库中
层?还是使用中心配置?@ChrisPaynter:10被烘焙到类定义中。所有的层都依赖于对象来确定它是否有效。啊,非常感谢。所以我猜你是在用一个public const int吗?@chrislive你能举个例子来支持你的答案吗?我的意思是更新您的答案,其中包含一个示例,说明其他层如何依赖于您为其设置属性的对象。那会更清楚…@ChrisPaynter:不。请看更新。我认为代码示例会更有意义。