Asp.Net MVC实践 (基于ASP.NET MVC Preview 2)

以前一直对.Net的表现业务感觉不爽,上次和Forever讨论很久,也没能很好的解决表现成业务分离的问题,最近看到了新的Asp.Net MVC框架,恍然茅塞顿开,原来如此,以前的WebForm基于MVP方式,这次新的MVC框架将表现成很轻松的分离这些业务.

Ok,今天我就来试着用MVC的方式写一个小的Demo程序,这个程序非常简单,就是一个Article的发布和浏览程序,程序有两个表,分别是category和content,分别是分类表,文章表,程序使用MySql数据库,建表脚本如下:

 

SQL代码
  1. create table `category`(   
  2.     `id` int primary key not null auto_increment,   
  3.     `namevarchar(255) not null,   
  4.     `intro` varchar(1024),   
  5.     `orderint default 1000,   
  6.     `url` varchar(255),   
  7.     `isurl` bit not null default 0   
  8. );   
  9. ALTER TABLE `category` ADD INDEX ( `order` ) ;   
  10.   
  11. create table `content`(   
  12.     `id` int primary key not null auto_increment,   
  13.     `categoryid` int not null,   
  14.     `title` varchar(255) not null,   
  15.     `info` varchar(1024),   
  16.     `content` text,   
  17.     `posttime` datetime not null,   
  18.     `postuser` varchar(50),   
  19.     `hits` int not null default 0   
  20. );   
  21. ALTER TABLE `content` ADD INDEX ( `categoryid` ) ;   
  22. ALTER TABLE `content` ADD INDEX ( `postuser` ) ;   
  23. ALTER TABLE `content` ADD INDEX ( `hits` ) ;   
  24.   
  25. insert into `category`(`name`,`intro`,`order`,`url`,`isurl`) values  
  26. ('Index','Index Page',0,'/default.aspx',1),   
  27. ('News','业界新闻',1,'',0),   
  28. ('.Net','.Net开发',2,'',0),   
  29. ('Asp.Net MVC','Asp.Net MVC',3,'',0),   
  30. ('C/C++','C/C++开发',4,'',0);   
  31.   
  32. insert into `content`(`categoryid`,`title`,`info`,`content`,`posttime`,`postuser`,`hits`) values  
  33. (2,'MvcArticle System 1.0发布','MvcArticle System 1.0发布','经过一段时间的开发,MvcArticle System 1.0发布终于发布.',NOW(),'Leven',0);   

在程序中,我创建一个HttpModule来初始化整个UrlRouting部分.UrlRouting初始化代码如下:

C#代码
  1. private static void InitRoutingUrls(RouteCollection routes)   
  2.         {   
  3.             routes.Add(new Route(string.Format("article{0}/list/{{category}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  4.             {   
  5.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "list", category = "0", page = "1" }),   
  6.                 Constraints = new RouteValueDictionary(new { category = "d+", page = "d+" }),   
  7.             });   
  8.             routes.Add(new Route(string.Format("article{0}/index/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  9.             {   
  10.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),   
  11.                 Constraints = new RouteValueDictionary(new { page = "d+" }),   
  12.             });   
  13.             routes.Add(new Route(string.Format("article{0}/view/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  14.             {   
  15.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "view", id = "1" }),   
  16.                 Constraints = new RouteValueDictionary(new { id = "d+" }),   
  17.             });   
  18.             routes.Add(new Route(string.Format("article{0}/add", WebConfig.MvcHandle), new MvcRouteHandler())   
  19.             {   
  20.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "add" }),   
  21.             });   
  22.             routes.Add(new Route(string.Format("article{0}/edit/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  23.             {   
  24.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "edit", id = "0" }),   
  25.                 Constraints = new RouteValueDictionary(new { id = "d+" }),   
  26.             });   
  27.             routes.Add(new Route(string.Format("article{0}/delete/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  28.             {   
  29.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "delete", id = "0" }),   
  30.                 Constraints = new RouteValueDictionary(new { id = "d+" }),   
  31.             });   
  32.             routes.Add(new Route(string.Format("article{0}/{{action}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())   
  33.             {   
  34.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),   
  35.                 Constraints = new RouteValueDictionary(new { page = "d+" }),   
  36.             });   
  37.             routes.Add(new Route("default.aspx"new MvcRouteHandler())   
  38.             {   
  39.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),   
  40.             });   
  41.             routes.Add(new Route("index"new MvcRouteHandler())   
  42.             {   
  43.                 Defaults = new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),   
  44.             });   
  45.         }   
其中,routing部分是如”/article/list/{category}/page”的部分,它定义了url的格式,更加清晰表明页面的意义.Defaults是默认的值, Constraints是对参数的正则验证,为了使用Constraints,传入的参数必须是String类型的.

然后到Web.Config中添加HttpModule

 

XML/HTML代码
  1. <add name="UrlRouting" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing"/>  
  2.       <add name="UrlRoutingInit" type="MvcArticle.Web.Routing.RoutingModule, MvcArticle.Web"/>  
第一个是MVC框架的Routing模块,第二个HttpModule中则是初始化Rouring的(一般初始化在Globle.ascx中,本Demo只是使用了另外一个方法.)
接下来,我们来创建Controllers部分,在Controllers目录下建立ArticleController控制器,该控制器被自动映射在”{controller}=”article”的url上,即所有访问url为article/…/…的url都归该类处理.而该类中的方法被成为Action,自动映射在Url中的Action部分.比如我访问/article/list/1/1实际上执行的是ArticleController类的List方法,而且该方法有两个参数,在本例中是访问了ArticleController.List(int category,int page)方法.默认情况下,Controller类中的所有方法都是Action,这点和Mvc的先前版本不一样,如果某个方法你不想让用户访问到,则可以加上[NonAction]属性.
关于View部分,默认的View页面应该要继承自System.Web.Mvc.ViewPage类,该类有泛型版和非泛型版,很显然,在显示数据的时候优先使用泛型版,比如demo中的list.aspx中, public partial class index : System.Web.Mvc.ViewPage<IList<ArticleContent>>此处就可以看出Controller传给View的数据是IList<ArticleContent>类型的,代码更易于维护.在MVC中,由于没了PostBack的概念,因此服务器控件都失去了交互性,因此在View部分完全可以抛弃服务器控件了,当然,如果想使用表现控件还是可以的,在本Demo中,则是和官方例子一样回归到使用内嵌c#代码的方式显示,此方法虽然对程序可读性有影响,但是在显示程序时候更加灵活.需要说明的是,在继承自ViewPage的类中,ViewData代表了Controller部分传入的数据,比如上面的例子,ViewData就是IList<ArticleContent>的数据,因此可以非常方便的显示出来.同时由于aspx页面只为了显示数据,不包含业务逻辑,维护起来更显方便.

比如在上面的index类中,循环显示ArticleCotent数据的代码如下:

 

XML/HTML代码
  1. <%   
  2.             foreach (ArticleContent content in ViewData)   
  3.             {   
  4.                 foreach (ArticleCategory cate in MvcArticle.Services.ServicesFactory.GetCategoryServices().Get())   
  5.                 {   
  6.                     if (cate.ID == content.CategoryID)   
  7.                     {   
  8.                         content.Category = cate;   
  9.                     }   
  10.                 }   
  11.         %>  
  12.         <div class="body_list_item">  
  13.             <div class="item_head">  
  14.                 <%=Html.ActionLink(content.Title, "view",new System.Web.Routing.RouteValueDictionary(new {controller="article"id=content.ID.ToString()}))%><span>作者:<%=content.PostUser %> 日期:<%=content.PostTime %></span>  
  15.             </div>  
  16.             <div class="item_body">  
  17.                 <%=content.Info %>  
  18.             </div>  
  19.             <div class="item_bottom">  
  20.                 分类: <%=Html.ActionLink(content.Category.Name, "list", new System.Web.Routing.RouteValueDictionary(new { controller = "article"category = content.CategoryID.ToString(), page = "1" }))%>  
  21.                 | Hits:<%=content.Hits %>  
  22.                 | <%=Html.ActionLink("编辑", "edit", new System.Web.Routing.RouteValueDictionary(new { controller = "article"id = content.ID.ToString() })) %>  
  23.                 | <a href="<%=Url.Action("delete", new System.Web.Routing.RouteValueDictionary(new { controller = "article", id = content.ID.ToString() })) %>" onclick="if (!window.confirm('是否要删除该文章')) return false;" title="删除该文章">删除</a>  
  24.             </div>  
  25.         </div>  
  26.         <%   
  27.             }   
  28.         %>  
由于UrlRouting的Url是层层深入的,因此页面引用其他文件的路径成了一个问题,在MVC框架中,引入了HtmlHelper和UrlHelper类来解决这个问题,在本版的MVC程序中,比如在程序中在本页面中,获取文章所在分类的分页浏览页面的url,使用的是<%=Html.ActionLink(content.Category.Name, "list", new System.Web.Routing.RouteValueDictionary(new { controller = "article", category = content.CategoryID.ToString(), page = "1" }))%>,这儿使用controller,action等数据组合的方式让程序生成url,很好解决了url问题.如果觉得这个方式生成的url不满足要求,则可以使用UrlHelper来自定义,比如上面的删除文章链接,使用的便是<a href="<%=Url.Action("delete", new System.Web.Routing.RouteValueDictionary(new { controller = "article", id = content.ID.ToString() })) %>" onclick="if (!window.confirm('是否要删除该文章')) return false;" title="删除该文章">删除</a>
 

最后是关于数据的提交,有两个办法,一个是在Controller的方法中访问Request对象,这个Request对象和WebForm中的保持一致,可以获取Form或者QueryString的内容,当时,更省事的方法是直接对Action方法定义参数,比如Demo的Save方法: public void Save(string title, int categoryid, string postuser, string info, string content)明确定义需要给出title等参数,要post给这种方法,你的aspx中相应的要有这些值,如果没有或者名称不同,则不会获取到你需要的值,比如在要调用该方法的add.aspx中,就分别有name为title,categoryid等的html表单,在提交的时候系统会自动将数据提交给Save方法的参数.
程序执行首页样式示例:

最后给出该Demo的源代码下载(仅MVC部分):
下载文件点击下载此文件



文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: .net  asp.net  C#  mvc 
评论: 0 | 引用: 0 | 查看次数: 675
发表评论
用户名:
密 码: 游客发言不需要密码.
验证码: 验证码
内 容:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 500 字 | HTML代码允许 关闭 | 评论可修改 关闭