MVCvalidation – 使用服务层保持干燥 – 最佳做法是什么?

我试图坚持最好的多层设计实践,并且不希望我的MVC控制器与我的DAL(或任何IRepository)进行交互。 它必须通过我的业务服务层来执行适当的业务规则和validation。 validation – 我不想在我的域模型实体上使用各种validation属性(例如[必需])在控制器中执行validation,因为这揭示了我的前端。 更不用说这项服务也可以通过WPF前端实现。

由于我的validation是在我的服务层完成的,将值返回给UI的最佳做法是什么? 我不想要’void addWhatever(int somethingsID)’,因为我需要知道它是否失败了。 它应该是一个布尔值吗? 它应该是枚举吗? 我应该利用exception处理吗? 或者我应该在将validation属性装饰到Model对象时返回一些类似于MVC使用的IValidationDictionary对象? (如果需要,我可以在UI中使用适配器模式)

我想将我的实体从控制器传递到服务层,并了解validation/数据持久性是否失败。 我也不想忽视这样一个事实:我需要返回一个视图,指出可能validation失败的每个字段的正确错误消息(我希望尽可能保持无痛)。

我有几个想法,所有这些想法都不对。 我觉得答案包括特定于视图的模型实体,但这会导致必须处理的整个映射问题,更不用说这违反了DRY(不要重复自己)原则。 什么是最佳做法?

我知道,似乎做MVCvalidation违反DRY,但实际上……它不会……至少不适用于大多数(非平凡的)应用程序。

为什么? 因为您的视图的validation要求通常与业务对象validation要求不同。 您的视图validation涉及validation特定视图是否有效,而不是您的业务模型是有效的。

有时这两者是相同的,但如果您构建应用程序以使视图要求业务模型有效,那么您将自己锁定在这种情况中。 如果您需要将对象创建拆分为两个页面,会发生什么? 如果您决定将服务层用于Web服务,会发生什么? 通过将您的UI锁定到业务层validation方案中,您可以严重削弱您可以提供的各种解决方案。

视图是输入的validation,而不是模型的validation。

这就是我做到的。

让您的服务层在业务规则/validation规则失败时抛出exception。 为此创建自己的validationexception,并包含一些属性来保存validation错误的详细信息 – (例如,哪个属性具有validation错误,以及消息是什么)

然后在Exception上创建一个扩展方法,它将错误的细节复制到ModelState(我从Steve Sandersons那里得到了相当优秀的’Pro Asp.Net MVC 2 Framework’一书) – 如果你这样做,MVC将突出显示无效字段,在UI等中显示错误

然后你的控制器将包含这样的东西

 try { Service.DoSomeThing(); } catch (Exception err) { err.CopyTo(ModelState); } 

这意味着您的业务规则和validation现在位于服务层中,并且可以重复使用。

考虑将DTO / View模型传递给您的视图,并将您的域对象映射到DTO和(反之亦然),而不是将您的域对象传递给您的视图。

然后DTO / View模型可以驻留在MVC层中,您可以使用Validation属性来装饰它们,并让控制器将这些属性传递给视图 – 从而使用内置的MVCvalidation。

您会发现,对于任何复杂的项目,UI端所需的validation可能与业务规则结束时所需的validation略有不同,因此这有助于分离。

有一个很好的名为AutoMapper的库,它可以很容易地从你的域对象映射到你的DTO(反之亦然),而不需要很多样板代码。

我建议您通过使用数据注释修饰Model类来利用内置的MVCvalidation。 这仅适用于与处理业务规则和validation不同的基本输入validation。 数据注释很棒,因为它们对任何知道但不会对不了解如何使用它们的消费者产生负面影响的消费者有用。

我认为使用服务层来抽象业务规则和数据访问是正确的。 您可能希望做一些事情来增强控制器和服务之间的交互:

  1. 返回XXXResult对象而不是void或primatives。 如果您的服务方法是AddProduct,则返回AddProductResult或更广泛的ProductServiceOperationResult。 此结果包含成功/失败指示符以及其他信息。

  2. 如果您使用的是WCF,则使用故障合同和例外。

我的典型MVC应用程序解决方案如下所示:

  • MVC网站项目
  • xxx.Model(项目,大多数图层引用)
  • xxx.Services(项目)
  • xxx.DataAccess(项目,有时与服务合并)
  • 其他人根据需要

祝好运!

这里的问题是服务层validation,但如何将这些信息“备份”到Web应用程序。 我们讨论了类似的东西,因为dependency injection的想法在这里明确起作用,如果服务正在validation,你不能在模型中调用服务(例如,如果在那里实现了IValidateableObject,你不想调用服务直)

采取的方法是:

选项3:我之前不知道这一点,但似乎是一种非常强大的编写validation器的方法是使用ModelValidator类和相应的ModelValidatorProvider。

ASP.NET MVC 3:在需要模型外部信息时validation模型

所以基本上你是注入一个validation器(然后在你的服务层),由mvc解析,而不需要显式的服务定位器调用。

斯蒂芬建议在这种情况下是完美的。 目前,我正在研究一个非常大的MVC 3.0应用程序,其中包含SOA和其他内容。 因此,在回复中,您希望填写所有必要的信息并将其显示给您的观点(当然控制器将指示)。 希望这可以帮助。

在几个层(客户端,控制器中的服务器端或等效层,以及业务层中)重复运行validation实际上并不是件坏事。 它使您的代码有点脱钩。 理想情况下,您只需要在一个地方描述它们,但有时这是不可能的。 由于未能使用数据注释,如果您想进行客户端validation,您是否真的很难自己? 看来是这样。

无论如何,我过去在非mvc应用程序中所做的就是让大多数操作方法返回一个Response对象,该对象包括状态(成功,错误,警告)和validation错误列表,以及所需的任何其他属性。

您可能能够利用IValidateableObject接口,但这再次将您与某些特定于ASP.net的东西联系在一起。 也许折衷方案是使用您的响应对象并转换为特定于DataAnnotation的错误。