载入中,请稍候……

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

Admin 于 2008-08-26 04:16:23 发表转载

订阅: http://www.miniboke.com/Feed/Article_11.aspx
引用: http://www.miniboke.com/Trackback/ePxcmgoMYsMnpAxwlJCZ.aspx (UTF-8)
网站推广的100个实用方法 < Asp.Net MVC实践 (基于ASP.NET MVC Preview 2) > Asp.Net MVC实践 - 自定义ActionResult实现Rss输出 (基于ASP.NET MVC Preview 3)

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

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

create table `category`(
    `id` 
int primary key not null auto_increment,
    `name` 
varchar(255not null,
    `intro` 
varchar(1024),
    `
orderint default 1000,
    `url` 
varchar(255),
    `isurl` 
bit not null default 0
);
ALTER TABLE `category` ADD INDEX ( `order` ) ;

create table `content`(
    `id` 
int primary key not null auto_increment,
    `categoryid` 
int not null,
    `title` 
varchar(255not null,
    `info` 
varchar(1024),
    `content` 
text,
    `posttime` 
datetime not null,
    `postuser` 
varchar(50),
    `hits` 
int not null default 0
);
ALTER TABLE `content` ADD INDEX ( `categoryid` ) ;
ALTER TABLE `content` ADD INDEX ( `postuser` ) ;
ALTER TABLE `content` ADD INDEX ( `hits` ) ;

insert into `category`(`name`,`intro`,`order`,`url`,`isurl`) values
(
'Index','Index Page',0,'/default.aspx',1),
(
'News','业界新闻',1,'',0),
(
'.Net','.Net开发',2,'',0),
(
'Asp.Net MVC','Asp.Net MVC',3,'',0),
(
'C/C++','C/C++开发',4,'',0);

insert into `content`(`categoryid`,`title`,`info`,`content`,`posttime`,`postuser`,`hits`) values
(
2,'MvcArticle System 1.0发布','MvcArticle System 1.0发布','经过一段时间的开发,MvcArticle System 1.0发布终于发布.',NOW(),'Leven',0);

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

private static void InitRoutingUrls(RouteCollection routes)
        
{
            routes.Add(
new Route(string.Format("article{0}/list/{{category}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "list", category = "0", page = "1" }),
                Constraints 
= new RouteValueDictionary(new { category = "\\d+", page = "\\d+" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/index/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),
                Constraints 
= new RouteValueDictionary(new { page = "\\d+" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/view/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "view", id = "1" }),
                Constraints 
= new RouteValueDictionary(new { id = "\\d+" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/add", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "add" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/edit/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "edit", id = "0" }),
                Constraints 
= new RouteValueDictionary(new { id = "\\d+" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/delete/{{id}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "delete", id = "0" }),
                Constraints 
= new RouteValueDictionary(new { id = "\\d+" }),
            }
);
            routes.Add(
new Route(string.Format("article{0}/{{action}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),
                Constraints 
= new RouteValueDictionary(new { page = "\\d+" }),
            }
);
            routes.Add(
new Route("default.aspx"new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),
            }
);
            routes.Add(
new Route("index"new MvcRouteHandler())
            
{
                Defaults 
= new RouteValueDictionary(new { controller = "article", action = "index", page = "1" }),
            }
);
        }


 

其中,routing部分是如”/article/list/{category}/page”的部分,它定义了url的格式,更加清晰表明页面的意义.Defaults是默认的值, Constraints是对参数的正则验证,为了使用Constraints,传入的参数必须是String类型的.

然后到Web.Config中添加HttpModule

<add name="UrlRouting" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing"/>
<add name="UrlRoutingInit" type="MvcArticle.Web.Routing.RoutingModule, MvcArticle.Web"/>

 
第一个是MVC框架的Routing模块,第二个HttpModule中则是初始化Rouring(一般初始化在Globle.ascx,Demo只是使用了另外一个方法.)

接下来,我们来创建Controllers部分,Controllers目录下建立ArticleController控制器,该控制器被自动映射在”{controller}=”article”url,即所有访问urlarticle/…/…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数据的代码如下:

 

<%
            foreach (ArticleContent content in ViewData)
            {
                foreach (ArticleCategory cate in MvcArticle.Services.ServicesFactory.GetCategoryServices().Get())
                {
                    
if (cate.ID == content.CategoryID)
                    {
                        content.Category 
= cate;
                    }
                }
        
%>
        
<div class="body_list_item">
            
<div class="item_head">
                
<%=Html.ActionLink(content.Title, "view",new System.Web.Routing.RouteValueDictionary(new {controller="article", id=content.ID.ToString()}))%><span>作者:<%=content.PostUser %> 日期:<%=content.PostTime %></span>
            
</div>
            
<div class="item_body">
                
<%=content.Info %>
            
</div>
            
<div class="item_bottom">
                分类: 
<%=Html.ActionLink(content.Category.Name, "list"new System.Web.Routing.RouteValueDictionary(new { controller = "article", category = content.CategoryID.ToString(), page = "1" }))%>
                | Hits:
<%=content.Hits %>
                | 
<%=Html.ActionLink("编辑""edit"new System.Web.Routing.RouteValueDictionary(new { controller = "article", id = content.ID.ToString() })) %>
                | 
<href="<%=Url.Action("delete", new System.Web.Routing.RouteValueDictionary(new { controller = "article", id = content.ID.ToString() })) %>" onclick="if (!window.confirm('是否要删除该文章')) return false;" title="删除该文章">删除</a>
            
</div>
        
</div>
        
<%
            }
        
%>

 

    由于UrlRoutingUrl是层层深入的,因此页面引用其他文件的路径成了一个问题,MVC框架中,引入了HtmlHelperUrlHelper类来解决这个问题,在本版的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方法定义参数,比如DemoSave方法: public void Save(string title, int categoryid, string postuser, string info, string content)明确定义需要给出title等参数,post给这种方法,你的aspx中相应的要有这些值,如果没有或者名称不同,则不会获取到你需要的值,比如在要调用该方法的add.aspx,就分别有nametitle,categoryid等的html表单,在提交的时候系统会自动将数据提交给Save方法的参数.

程序执行后首页示例:

同步更新地址:http://blog.leven.com.cn/Article_27.aspx
最后给出该
Demo的源代码下载(MVC实现部分):

http://files.cnblogs.com/leven/public.rar

Tag标签: asp.net,c#,mvc
 posted on 2008-05-27 22:46 Leven 阅读(2058) 评论(8)  编辑 收藏 所属分类: Asp.Net MVC

#1楼     回复  引用  查看    
 五味果       | 2008-05-28 01:34
传说中的沙发,顶了再细看!
#2楼     回复  引用  查看    
 Q.Lee.lulu       | 2008-05-28 08:19
"默认情况下,Controller类中的所有方法都是Action"

public的方法才是的......
#3楼     回复  引用  查看    
 第一控制.NET       | 2008-05-28 08:45
楼上所言极是。。。
#4楼 [楼主]    回复  引用  查看    
 Leven       | 2008-05-28 17:42
楼上两位说的正确,恕我描述疏忽了,呵呵.
#5楼     回复  引用  查看    
 Solog       | 2008-05-29 09:24
我们已经用MVC PRIVIEW2在做项目了。
看了你的文章还有粗略看了LZ的代码。有些问题请教:

1.对于你的URL映射感觉很独特,我是用Globle.ascx初始化那些规则的。
而且看LZ的Controler方式,可以接收好几个参数。有点像preview3里面的特性。P2里我不是这样用的。所以没看明白。
routes.Add(new Route(string.Format("article{0}/list/{{category}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "article", action = "list", category = "0", page = "1" }),
Constraints = new RouteValueDictionary(new { category = "\\d+", page = "\\d+" }),
});
WebConfig.MvcHandle主要这个没看懂。。。。

2.LZ的controler中,操作,比如删除添加,成功后
用 Message(msg)的方式,感觉不太好。还得用户链接返回。
 
#6楼 [楼主]    回复  引用  查看    
 Leven       | 2008-05-29 16:14
@Solog
首先我认为用priview版做项目未免也太超前了,现在mvc每个版本都有蛮大变化的.而且bug也不少
问题一个个说:
1.url映射的问题,大家都是在Globle.ascx中做的,我只是做下测试看是否可以通过其他途径实现而且,这个完全看各自喜好.添加 url映射这个地方其实和priview3还是有很大区别的.priview2使用我这样的模式添加,priview3中提供更加方便的MapRoute 方法,其实这儿的几个参数和MapRoute的参数差不多,注意这而Add的语法,两个大括号的Defaults等是设置Route的对应属性的,实际等 同于:
Route route=new Route(string.Format("article{0}/list/{{category}}/{{page}}", WebConfig.MvcHandle), new MvcRouteHandler();
route.Defaults=xxx;
route.Constraints=xxx;
routes.Add(route);
至于MvcHandle这个,主要是为了方便在iis上发布程序使用,iis7我不知道,但是iis6默认是没有添加无扩展名的.net扩展的, 如果像是在虚拟主机没有权限操作iis,默认是无法支持这种url的,于是可以设置一个.net的扩展名来支持,比如将这儿MvcHandle设置 为".ashx"则访问路径变为"xxx.ashx/action/xxx"之类的.
2.controller操作返回问题,一般来说用户有数据提交后会给出一个返回信息吧,流行的自然是ajax来个信息框之类的,我这个简单 demo只是用了一个简单的Message页面,这也是常用的办法,不过这个方法不大好,只是priview中折中的方式,如果在priview3中,更 好的方式是定制自己的ActionResult来处理这个问题.
#7楼     回复  引用  查看    
 Solog       | 2008-05-30 11:51
@Leven
谢谢楼主的回复。
今天在IIS6上部署,吃了不少苦头。
preview2有很多BUG。,p3看了看并没有升级了。
建议大家不要用了,呵呵。等正式版吧。
#8楼 [楼主]    回复  引用  查看    
 Leven       | 2008-05-30 12:37
@Solog
呵呵,iis6部署啊,其实设置下也可以了,只需要添加个通配符应用程序映射就可以实现无扩展名urlrouting,记得园子里有人提过.不过现在用这个框架的确有点早.

被阅759次, 0投一票Asp.Net MVC
  • 看完了要说点啥么?
  • 昵称 (不填说不了话)
  • 信箱地址 (不会被公开,但是不填也说不了话)
  • 网址 (这个不填也成)

Powered by MiniBoke v2.0.0.8 Build 0828

Copyright © 2008 迷你博客. All rights reserved.

粤ICP备07500939号