ASP.NET MVC 3 Model的使用?

  昨天博客发了新文章,讲一下我对如何使用MVC中的Model的看法,不是什么大技术,当是一个技术讨论^^

  原文地址:http://www.youguanbumen.net/Article.aspx?id=79

  原文:

  前两天写了个文章ASP.NET MVC 3 —— Model远程验证,主要记录了一下ASP.NET MVC 3中新增的RemoteAttribute类的使用,得益于这个类,我们可以在模型中为属性配置客户端远程校验的业务,文章中给了出一个简单的实体类MyUser_Add,举了一个最常见的注册用户时验证用户名是否存在的例子,最后成功地对用户名实现了用ajax加薪校验的功能。给出Model的代码如下:

1. /// summary

2. /// 用户添加操作的模型

3. /// /summary

4. publicclassMyUser_AddModel

5. {

6. #region MyRegion

7. /// summary

8. /// 用户名

9. /// /summary

10. [DisplayName("登录账号")]

11. [Required(ErrorMessage = "用户账号不能为空")]

12. [Remote("CheckUserAccountExists", "Test", ErrorMessage = "用户账号已存在")]

13. // 远程验证(Ajax)

14. publicstringUserAccount { get; set; }

15. }

  文章发到博客园上面之后有朋友提出一了一点:这个我们可以认为在创建的时候解决重复问题,但是如果是Update的话,我相信这样的语句应该也会报错误的。就是说如果这个Model用于做Update操作的时候,校验用户名是否存在的方法和Add操作会有点不同,因为要把自己排除在外,例如原来的用户名叫user1修改后还叫user1,这时候判断用户名是否存在的标准是如果存在用户名是user1的并且用户ID号不是当前这个要修改的用户,那么用户不可用(存在),而Add操作的时候不存在自己,所以我看可以理解为两个操作都需要判断用户名是否存在,但是使用了不同的策略!

  刚好之前看了ASP.NET MVC 3自带的Demo(就是创建MVC3.0项目后生成的那个- -!),想写一下我自己认为的微软希望我们怎么去设计MVC中的Model的看法,发现似乎和这个问题有点联系,以下是我个人的观点:

  首先我们看下Demo项目中Models目录下的AccountModels.cs,下面的代码摘自这个文件中的两个我认为很有代表性的类,都是和用户有关的,源代码如下:

1. publicclassLogOnModel

2. {

3. [Required]

4. [Display(Name = "User name")]

5. publicstringUserName { get; set; }

6. [Required]

7. [DataType(DataType.Password)]

8. [Display(Name = "Password")]

9. publicstringPassword { get; set; }

10. [Display(Name = "Remember me?")]

11. publicboolRememberMe { get; set; }

12. }

13. publicclassRegisterModel

14. {

15. [Required]

16. [Display(Name = "User name")]

17. publicstringUserName { get; set; }

18. [Required]

19. [DataType(DataType.EmailAddress)]

20. [Display(Name = "Email address")]

21. publicstringEmail { get; set; }

22. [Required]

23. [ValidatePasswordLength]

24. [DataType(DataType.Password)]

25. [Display(Name = "Password")]

26. publicstringPassword { get; set; }

27. [DataType(DataType.Password)]

28. [Display(Name = "Confirm password")]

29. [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]

30. publicstringConfirmPassword { get; set; }

31. }

  注意上面两个类的类名,我们很容易读懂一个是(用户)登录模型,一个是(用户)注册模型,有意思的地方在于两个类都用UserName、Password两个属性,UserName的验证方式完全一样,而Password有所不同,RegisterModel中多了一个ValidatePasswordLengthAttribute的特性——一个自定义验证特性。这两个模型对应的是不同的Action-View,于是我的理解是:Model是为了Actioin-View而存在的。例如,有一个页面是用来显示一张表单,这张表单会被提交到一个介绍Post请求的Action中,这时候就会创建一个和这个表单对应的Model,用来在View和Action中充当媒介的作用(所谓的实体传参)。

  回到上面那个检测用户名是否存在的问题,基于这个想法可以得出一个解决方案,那就是创建另外一个新类,叫做MyUser_UpdateModel(用户修改模型),可以得出以下的代码

1. publicclassMyUser_UpdateModel

2. {

3. /// summary

4. /// 用户名

5. /// /summary

6. [DisplayName("登录账号")]

7. [Required(ErrorMessage = "用户账号不能为空")]

8. [ValidateUserAccountAttribute] // 自定义验证

9. [Remote("CheckUserAccountExistsForUpdate", "Test", ErrorMessage = "用户账号已存在")]

// 远程验证(Ajax)

10. publicstringUserAccount { get; set; }

11. }

  注意到远程验证调用的是另外一个Action,这个Action的代码如下:

1. /// summary

2. /// 用于验证用户账号是否存在的Action(Update操作时使用)

3. /// /summary

4. /// param name="UserAccount"用户账号/param

5. /// returns/returns

6. [HttpGet]

7. public ActionResult CheckUserAccountExistsForUpdate(string UserAccount)

8. {

9. var ms = ModelState;

10. string[] existsUsers = { "wodanwojun" };

11. bool exists = string.IsNullOrEmpty(existsUsers.FirstOrDefault(u = u.ToLower() == UserAccount.ToLower())) == false;

12. return Json(!exists, JsonRequestBehavior.AllowGet);

13. }

14.

15.

16.

17.

18. public class MyUser_UpdateModel

19. {

20. /// summary

21. /// 用户名

22. /// /summary

23. [DisplayName("登录账号")]

24. [Required(ErrorMessage = "用户账号不能为空")]

25. [ValidateUserAccountAttribute] // 自定义验证

26. [Remote("CheckUserAccountExistsForUpdate", "Test", ErrorMessage = "用户账号已存在")] // 远程验证(Ajax)

27. public string UserAccount { get; set; }

28. }

  这里假设要修改的用户的用户名叫做youguanbumen,所以验证的时候如果输入了有关部门是不应该提示该账号已存在的(因为就是他自己,用了这个账号是没问题的)。控制器的代码我就不写咯,大致就是得到一个用户名叫做youguanbumen的Model——MyUser_UpdateModel类,然后通过return View(object model)方法丢给View(当然,View是强类型的——MyUser_UpdateModel类),测试结果截图如下:

  1、输入wodanwojun作为用户名,发现通不过,就像下面这张截图这样,原因请见上面的代码!

  2、输入youguanbumen作为用户名。发现没有错误提示,就像下面这张截图这样,原因请见上面的代码,并对照前一篇文章中另外一个用于远程校验的Action的代码!

  总结一下:似乎写出来的每一篇文章都不短但是讲的东西都很少,呵呵,请别介意^_^。虽然写代码的经验很不多,但是个人对于代码还是有一些自己的看法的。选择一个框架来开发一个系统,就意味着在开发的过程中你需要遵循某些约定好的东西,例如选择WebForm来开发系统,就尽量的接受事件相应和服务器端控件;选择了MVC就要接受把C#代码嵌到页面去的这个事实,当然如果使用了某些RIA框架后可能不出现这种情况(因为页面上的东西基本都是异步请求回来的)。

  特别是多人开发的时候,我们有必要遵循某些套路来写代码,例如上面这个例子,也许写Model、写View和写Action是三个不同的人来完成的时候,如果遵循这一个Action会有一个Model来支持它的这种套路来走的话,每个人都很容易找到代码的下手点,写View的人知道如何去声明页面为强类型(他会去找相关的Model),写Action的人知道return View(object model)中的model是啥,也知道用于处理Post的Action的参数是什么,写Model的人需要很了解业务,知道哪些字段是必填的,那些字段有长度限制等等,但是他也许不知道这个Model会被拿去怎么展示!

  ASP.NET MVC中的Model是和业务紧密相关的,有什么样的业务需求就会产生什么样的Model,并且会有相应的Action来出来它,有相应的View来展示它。如果基于这个想法来开发系统的话,很有可能得出这样一个简要的开发流程:研究业务--转化为对应的Model,根据业务需求对Model的属性配置验证特性--设计数据库表来对数据进行存放(也许是xml也不一定)--设计View来展示它,设计Action来处理它......。

时间: 2024-09-20 20:54:56

ASP.NET MVC 3 Model的使用?的相关文章

ASP.NET MVC的Model、DTO、Command的区别

最近在用CQRS架构模式做项目,有些感悟,记录下来. 问题的描述(大家是否也存在过类似的情况呢?): 从刚开始时项目中没有区分这3种对象,所以导致了很多职责公用,然后就乱了,比如Command一部分职责 需要用到ASP.NET MVC中,所以定义在了底层dll中,并且贴了一堆一堆的DataAnnotation的tag到属性上,其 中包括了很多remote验证.前端js validation组件的验证tag,很宏伟.后端CommandHandler那边传入 DomainService的dll中,由

ASP.NET MVC的Model元数据提供机制的实现

在前面的介绍中我们已经提到过表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider的组件提供的,接下来我们着重讨论基于ModelMetadataProvider的Model元数据提供机制及其扩展. 一. ModelMetadataProvider 在ASP.NET MVC的Model元数据相关的应用编程接口中,用于创建Model元数据的ModelMetadataProvider接继承自抽象类ModelMetadataProvider.如下

通过实例模拟ASP.NET MVC的Model绑定机制:数组

[续<通过实例模拟ASP.NET MVC的Model绑定机制:简单类型+复杂类型]>]基于数组和集合类型的Model绑定机制比较类似,对于绑定参数类型或者参数类型的某个属性为数组或者集合,如果ValueProvider根据对应的Key能够匹配多条数据,那么这些数据最终将会转换为绑定的数组/集合的元素.此外,针对数组/集合的Model绑定还支持基于索引的方式.[源代码从这里下载] 一.基于名称的数组绑定 对于针对NameValueConllectionProvider来说,通过GetValue方

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子.[本文已经同步到<How ASP.NET MVC Works?>中] 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子. 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等.对于ASP.NET MVC来说,我们可以通过HtmlHelper/H

ASP.NET MVC的Model元数据与Model模板:预定义模板

通过ModelMetadata表示的Model元数据的一个主要的作用在于为定义在HtmlHelper和HtmlHelper<TModel>中的模板方法(这些模板方法包括Display/DisplayFor.Editor/EditorFor.DisplayForModel/EditForModel.Lable/LabelFor和DisplayText/DisplayTextFor等)提供用于最终生成HTML的元数据信息.在调用这些方法的时候,如果我们指定了一个具体的通过分部View定义的模板,或

通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典

在本系列的前面两篇文章(<简单类型+复杂类型>.<数组>)我们通过创建的实例程序模拟了ASP.NET MVC默认使用的DefaultModelBinder对简单类型.复杂类型以及数组对象的Model绑定.现在我们按照相同的方式来分析基于集合和字典类型的Model绑定是如何实现的.[源代码从这里下载] 一.集合 这里的集合指的是除数组和字典之外的所有实现IEnumerable<T>接口的类型.和基于数组的Model绑定类似,ValueProvider可以将多个同名的数据项

通过实例模拟ASP.NET MVC的Model绑定机制:简单类型+复杂类型

总的来说,针对目标Action方法参数的Model绑定完全由组件ModelBinder来实现,在默认情况下使用的ModelBinder类型为DefaultModelBinder,接下来我们将按照逐层深入的方式介绍实现在DefaultModelBinder的默认Model绑定机制.[源代码从这里下载] 一.简单类型 对于旨在绑定目标Action方法参数值的Model来说,最简单的莫过于简单参数类型的情况.通过<初识Model元数据>的介绍我们知道,复杂类型和简单类型之间的区别仅仅在于是否支持针对

ASP.NET MVC的Model元数据与Model模板:模板的获取与执行策略

当我们调用HtmlHelper或者HtmlHelper<TModel>的模板方法对整个Model或者Model的某个数据成员以某种模式(显示模式或者编辑模式)进行呈现的时候,通过预先创建的代表Model元数据的ModelMetadata对象都可以找到相应的模板.如果模板对应着某个自定义的分部View,那么只需要执行该View即可:对于默认模板,则直接可以得到相应的HTML.本篇文章着重讨论模板的获取和执行机制,不过在这之前,顺便来讨论一下DataTypeAttribute和模板的关系. 一.