【asp源码栏目提醒】:网学会员asp源码为您提供基于ASP.NETMVC框架开发Web论坛应用程序(四).doc - 编程语言参考,解决您在基于ASP.NETMVC框架开发Web论坛应用程序(四).doc - 编程语言学习中工作中的难题,参考学习。
基于
ASP.NETMVC 框架开发 Web 论坛应用程序(四.2) 编译 朱先忠一、 简介 在上一篇文章中,我描述了如何在一个 MVC 应用程序中借助于定制校验属性来从服务器端对表单域执行校验。
通过使用属性(例如 RequiredValidator 和RegularExpressionValidator 属性)来修饰你的模型,你可以强制实施指定的校验规则并显示定制的校验错误消息。
为了执行更复杂的校验, 我曾推荐使用一个 CustomValidator 校验器,你可以把它应用于实体类的校验。
这个 CustomValidator 类是通过指向另一个类来最终执行定制的校验规则的。
但是,如果进行更细致的分析, 你会发现上述这个方法在应用于大多数场所下实现定制校验时还是比较复杂的。
因此,大多数开发人员可能更喜欢使用属性的方法进行校验但是,是否还存在更容易的方法进行定制校验呢? 在本篇中,我将采用与上面稍微不同的方法来处理表单校验的问题。
具体地说,我将把Scott Guthrie 所描述的命令式方法和上面的属性方法结合到一起。
换句话说,我将混合使用命令式和声明性方法来完成表单域的校验。
我称这个方法为实现表单校验的混合方法。
二、 使用命令式方法进行表单校验 让我们首先开始讨论 Scott Guthrie 所描述的方法。
当使用这个方法进行表单校验时,你必须创建下列类: IRuleEntity—这是为了进行校验每一个实体都必须实现的一个接口。
RuleViolation—这是一个描述校验错误的类。
RuleViolationException—这是当一个实体校验失败时引发的一个异常类。
Validation—这是类中包括了一个方法,用于把校验规则复制到 ModelState 中。
首先,上面这个 IRuleEntity 接口是相当简单。
名字为 Validate 它仅包含了两个方法,和 GetRuleViolations。
列表 1 中提供了这个接口的实现代码。
列表 1–IRuleEntity.csusing System.Collections.Genericnamespace MvcValidation public interface IRuleEntity List GetRuleViolations void Validate 该 RuleViolation 类描述了一个特定的校验错误。
在此,使用了一个 RuleViolations的集合来描述所有的校验错误(当提交一个表单时可能发生)。
列表 1 中提供了该RuleViolation 类的实现代码。
列表 2–RuleViolation.csusing Systemusing System.Collections.Genericusing System.Linqusing System.Webnamespace MvcValidation public class RuleViolation public string PropertyName get private set public object PropertyValue get private set public string ErrorMessage get private set public RuleViolationstring propertyName object propertyValue stringerrorMessage this.PropertyName propertyName this.PropertyValue propertyValue this.ErrorMessage errorMessage 即使存在一条规则被破坏的情况,也会引发一个 RuleViolationException 异常。
列表3 中提供了这个特别的异常类的实现代码。
列表 3–RuleViolationException.csusing Systemusing System.Collections.Genericnamespace MvcValidation public class RuleViolationException : Exception public RuleViolationExceptionstring message ListvalidationIssues : basemessage this.ValidationIssues validationIssues public List ValidationIssues get private set 最后请注意该 Validation 类是一个工具类,它暴露了一个名字为UpdateModelStateWithViolations的方法。
这个方法负责把所有的校验规则复制到一个控制器类的 ModelState 数据中。
列表 3 中提供了这个校验类的实现代码。
列表 4–Validation.csusing System.Web.Mvcnamespace MvcValidation public class Validation public static void UpdateModelStateWithViolationsRuleViolationExceptionruleViolationException ModelStateDictionary modelState foreach var issue in ruleViolationException.ValidationIssues var value issue.PropertyValue string.Empty modelState.AddModelErrorissue.PropertyName value.ToStringissue.ErrorMessage 让我们来看一下上面所有这些类是如何协同工作的。
首先注意到,列表 5 中的 Message类描述了一个论坛消息。
注意,这个类通过实现 Validate和 GetRuleViolations方法实现了 IRuleEntity 接口。
列表 5–Message.csusing Systemusing MvcValidationusing System.Collections.Genericusing System.Data.Linqusing MvcValidation.Attributesusing System.Web.Mvcnamespace MvcForums.Models.Entities public class Message :IRuleEntity private DateTime _entryDate DateTime.Now public Message public Messageint id int parentThreadId int parentMessageId stringauthor string subject string body this.Id id this.ParentThreadId parentThreadId this.ParentMessageId parentMessageId this.Author author this.Subject subject this.Body body public int Id get set public int ParentThreadId get set public int ParentMessageId get set public string Author get set public string Subject get set public string Body get set public DateTime EntryDate get return _entryDate set _entryDate value region IRuleEntity Members public List GetRuleViolations var validationIssues new List // Validate Subject if String.IsNullOrEmptythis.Subject validationIssues.Addnew RuleViolationsubject this.SubjectYou must enter a message subject. // Validate Body if String.IsNullOrEmptythis.Body validationIssues.Addnew RuleViolationbody this.Body Youmust enter a message body. return validationIssues public void Validate var validationIssues GetRuleViolations if validationIssues.Count 0 throw new RuleViolationExceptionValidation IssuesvalidationIssues endregion 请注意到,这个 Validate方法调用了另一个 GetRuleViolations方法。
如果存在任何校验错误,那么该 Validate方法即抛出一个 RuleViolationException 型异常。
在论坛应用程序中,该 Validate方法是在 ForumRepository 中被调用的。
在把一个新消息添加到数据库中之前在 Message 类上调用这个 Validate方法,如下所示:public Message AddMessageMessage messageToAdd messageToAdd.Validate _dataContext.InsertmessageToAdd return messageToAdd 如果存在一个校验错误,那么将抛出一个 RuleViolationException 型异常,并且永不会把相应的消息插入到数据库中。
该 ForumRepository 应用于论坛控制器内。
当你提交一个表单用以创建一个新的论坛消息时,ForumController.CreateFormCollection collecction方法即被调用。
列表 6 中提供了论坛控制器完整的实现代码。
列表 6–ForumController.csusing Systemusing System.Web.Mvcusing MvcForums.Modelsusing Microsoft.Web.Mvcusing MvcForums.Models.Entitiesusing MvcValidationnamespace MvcForums.Controllers public class ForumController : Controller private IForumRepository _repository public ForumController : thisnew ForumRepository public ForumControllerIForumRepository repository _repository repository public ActionResult Index ViewData.Model _repository.SelectThreads return ViewIndex AcceptVerbsGET public ActionResult Create return ViewCreate AcceptVerbsPost public ActionResult CreateFormCollection form var messageToCreate new Message try UpdateModelmessageToCreate new Author ParentThreadIdParentMessageId Subject Body _repository.AddMessagemessageToCreate catch RuleViolationException rex Validation.UpdateModelStateWithViolationsrexViewData.ModelState return ViewCreate messageToCreate catch Exception ex ViewData.ModelState.AddModelErrormessage null Could notsave message. return ViewCreate messageToCreate // Redirect return RedirectToActionIndex public ActionResult Threadint threadId ViewData.Model _repository.SelectMessagesthreadId return ViewThread 注意,这里存在两个 Create方法。
第一个 Create方法仅当发生一次 HTTP GET 操作时才被调用。
这个行为返回的表单将用于创建一个新的消息见图 1。
图 1–添加一个论坛消息的表单 当把一个 XHTML 表单回寄到服务器时调用第二个 Create方法。
当表单数据被回寄时,该 Create方法将调用控制器的 UpdateModel方法以便生成一个 Product 类(它把所有的表单值进行提交)。
接下来,调用 ForumRepository.Add方法以便把新的 Product 类实例添加到数据库。
注意,上述两个语句都包含在一个 Try..Catch 块内。
如果任意一个方法,无论是Controller.UpdateModel还是 ForumRepository.Add方法,失败,那么,即执行这个Try…Catch 语句的 Catch 子句。
第一个 Catch 子句使用校验错误信息更新ViewData.ModelState 属性(通过把校验错误从 RuleViolationException 复制到ModelState)。
接下来,重新显示 Create 视图。
注意,还存在两个 Catch 语句。
当 第二个 Catch 子句捕获一个泛型异常。
UpdateModel方法遇到一个校验错误时错误的类型值被赋给一个属性, 调用这个 Catch 子句。
当存在网络问题(例如你的数据库服务器或你的数据库服务器崩溃)时,将调用这个子句。
注意,一个名字为 message 的错误键也同时被更新。
列表 7 中提供了 Create 视图的完整的实现代码。
列表 7--Create.aspxSubject:Body: 注意上面的视图中包括了一个泛型错误消息名字为 message。
图 2—泛型错误消息 上述这个实现校验的方法是一种命令式编程方法。
该校验规则是通过GetRuleViolations方法中命令式的编程代码实现的,如下所示:public List GetRuleViolations var validationIssues new List // Validate Subject if String.IsNullOrEmptythis.Subject validationIssues.Addnew RuleViolationsubject this.Subject You mustenter a message subject. // Validate Body if String.IsNullOrEmptythis.Body validationIssues.Addnew RuleViolationbody this.Body You must entera message body. return validationIssues 使用命令式方法可以使你能够执行你所需要的任何类型的校验。
例如在把一条消息插入到数据库之前,你可以执行一个数据库查询以确保消息主题和正文在数据库中都是唯一的。
三、 使用声明性方法进行表单校验 一般的程序员都喜欢使用声明性方法实现表单校验。
声明性方法能够使你校验表单数据而不用编写任何代码。
使用声明性方法的另一个优点是, 声明性方法能够使你非常容易地实现客户端校验。
我们的一个想法是,从我们的服务器端校验器生成客户端校验器。
通过这种方式,我们可以校验一个表单而不必把表单回寄到服务器端。
列表 8 中修改过的 Message 类即使用一个声明性方法实现了有关表单域的校验。
列表 8–Message.csusing Systemusing MvcValidationusing System.Collections.Genericusing System.Data.Linqusing MvcValidation.Attributesusing System.Web.Mvcnamespace MvcForums.Models.Entities public class Message :IRuleEntity private DateTime _entryDate DateTime.Now public Message public Messageint id int parentThreadId int parentMessageId stringauthor string subject string body this.Id id this.ParentThreadId parentThreadId this.ParentMessageId parentMessageId this.Author author this.Subject subject this.Body body public int Id get set public int ParentThreadId get set public int ParentMessageId get set public string Author get set RequiredValidatorYou must enter a message subject. public string Subject get set RequiredValidatorYou must enter a message body. public string Body get set public DateTime EntryDate get return _entryDate set _entryDate value region IRuleEntity Members public List GetRuleViolations var validationIssues new List // Validate attributes AttributeValidation.Validatethis validationIssues return validationIssues public void Validate var validationIssues GetRuleViolations if validationIssues.Count 0 throw new RuleViolationExceptionValidation IssuesvalidationIssues endregion 在这个修改过的 Message 类中, 注意, Subject 和 Body 属性都修饰以 RequiredValidator属性。
借助于这个 RequiredValidator 属性,这两个属性成为必需提供的属性。
此外还请注意,已经从该 GetRuleViolations方法中删除了原先的命令式代码。
代之的是,AttributeValidation.Validate方法被调用。
这个方法针对每一个应用到 Message类上的校验器属性都调用 Validate方法。
如果至少一个校验器失败,那么该 Message 类校验即失败,并且抛出一个 RuleViolationException 型的异常。
很显然你可以混合使用属性和非属性方法进行校验。
对于普通的校验任务而言你可以使用标准校验器,例如 RequiredValidatorLengthValidator 或RegularExpressionValidator。
对于更复杂的类型校验你可以编写命令式代码以执行校验。
四、 总结 在本篇中,我描述了一种把命令式和声明性相结合进行校验的方法。
我相信,对于普通的校验任务方法最容易的方法应该是声明性方法。
但是,对于更复杂的或专门的类型校验任务,你应该编写命令式校验代码。
对于本系列文章中创建的论坛应用程序而言,我计划采取一种混合的方法实现最终的表单域的校验。
上一篇:
《ASP网络程序设计与应用》
下一篇:
经典心理语录净化心灵