您的位置:首页 > 编程语言 > ASP

ASP.NET MVC 1.0学习笔记

2009-05-16 09:52 573 查看
ASP.NET MVC 1.0刚新鲜出炉,头就让我用它做项目.说实话,一开始心里没底.虽然ASP.NET Web Form也说不上很熟,但好歹做过一阵,大致心里还是有底的.MVC除了个基本概念,具体的实现就一无所知了.不过心想学点新东西总是好的,大概也能对付着做出来,于是就试着用它做了起来.
第一件事是到ASP.NET MVC的官方主页下载了库,安装没什么问题.然后是找参考资料.由于它实在太新,电子书极少,好不容易只找到一本ASP.NET MVC In Action的预览版,一本ASP.NET MVC 1.0 Quickly, Professional Asp.net MVC Framework的第一章.先看ASP.NET MVC In Action,觉得不好懂,又看ASP.NET MVC 1.0 Quickly,开始觉得很好,脉络清晰,内容实用,但做了几天又觉得内容不够丰富,最后那本是一个实例,也不够实用.这样,很多东西只能靠google找答案.
和这个鬼东西搏斗了几天,总算略有开窍,写点体会:
1.MVC的基本概念:
主要目的是实现数据和数据的表现分离,减少耦合度,使程序更加灵活.视图(View)需要数据时,向控制器(Controller)发出请求,控制器通过模型(Model)获得数据,再设置视图的呈现形式.
2.ASP.NET MVC和原来的ASP.NET Web Form的主要区别:
原来的ASP.NET Web Form,基本上所有事件都发生在服务端,客户端通过Postback呼叫服务端,服务端处理后再把结果发给客户端.有很多服务端控件,编程模式和Win Form有很多类似之处,如事件驱动,控件丰富等.
而ASP.NET MVC则需要用户自己处理Postback,或者说,通过对Controller编程,来控制Postback,自然,这样灵活性增加了,也给了客户端更多的发挥余地.但是,由于取消了服务端控件,编程就不如Web Form方便,比如,没有了日历控件,只能自己用Javascript做一个;由于控制器所产生的视图在运行时(而不是设计时)才能看到,所见即所得的界面设计没有了.
还有一个很大的不同是ASP.NET MVC引入了路由(Routing)的概念.以前在Web Form里,一个URL就对应磁盘上一个物理的文件,而在MVC里,一个URL对应的是Controller里一个Action方法的名称.

3.ASP.NET MVC的基本结构:
1)客户端:
主要是HTML页面,虽然也是用aspx后缀,但没有web form里的codebehind,页面开头有一句:
< %@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
除了可以用标准的HTML元素和Javascript之外,还可以用HtmlHelper类来生成控件,如:
< table>
 < tr>
 < td>
 < %= Html.TextBox("txtCode", string.Empty, new {@id="txtCode", style="width:100px"}) %>
上面new后面的括号里是TextBox的HTML属性.
其实就等于:
< input type="text" name="txtCode" id="txtCode" value='' />
还有一个比较独特的元素叫ActionLink,作用类似HyperLink,只不过由于ASP.NET MVC里用到Routing的概念,所以连接指向的不是一个具体的物理文件,而是Controller类的一个方法.
2)服务端:
一个是Model,负责访问数据库,提供数据,这和普通的类区别不是很大.一个是Controller,负责和客户端的交互,把数据呈现到客户端,或者当客户端的显示出现变化时,调整后台数据,与其保持一致.
4.客户端和服务端的交互:
1)初始:
一般是在Default.aspx.cs里初始MVC,如果是用向导生成的话,Default.aspx.cs是唯一一个有codebehind和Page_Load事件的文件:
 string originalPath = Request.Path;
 HttpContext.Current.RewritePath(Request.ApplicationPath, false);
 IHttpHandler httpHandler = new MvcHttpHandler();
 httpHandler.ProcessRequest(HttpContext.Current);
 HttpContext.Current.RewritePath(originalPath, false);
其他页面必须在访问了这个Default.aspx之后才能访问,不然MVC未初始,将报错.
2)Routing:
负责处理这个Default.aspx页面的Controller放在Controllers目录下的HomeController.cs,内容很简单:
 [ HandleError]
 public class HomeController : Controller
 {
 public ActionResult Index()
 {
 //ViewData["Message"] = "Welcome to ASP.NET MVC!";

 return View();
 }

 public ActionResult About()
 {
 return View();
 }
那么MVC是如何找到这里的呢?
首先,在Web.config里有一个设置:
< add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
这个缺省的assembly就是负责routing的.
具体的routing设置,一般放在Global.asax.cs这个文件:
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 routes.MapRoute(
 "Default", // 路径名
 "{controller}/{action}/{id}", // 带参数的路径样式
 new { controller = "Home", action = "Index", id = "" } // 缺省的对应这个路径的controller和action以及缺省参数
 );
 }

 protected void Application_Start()
 {
 RegisterRoutes(RouteTable.Routes);
 }

比如http://localhost:2040/car/check 这个路径,MVC就会到Controller目录下找CarController.cs这个文件里的Check方法,如果找不到,就会转到HomeController.cs里的Index方法来处理.
这里要注意的是:
a.IIS 5.0(如2000和XP里所装的)似乎不支持所谓的wildcard mapping,就是说不支持对无后缀名(如.aspx, .cs)的URL的处理,所以不管怎么设置,都只能跑到缺省的HomeController里.解决这个问题的方法是定义一个后缀名,如.mvc,然后在IIS里,将.mvc和aspnet_isapi.dll关联起来,然后在Global.asax.cs里加一个路径映射:
 routes.MapRoute(
 "Myroute",
 "{controller}.mvc/{action}",
 new { controller = "MyController", action = "MyAction" }
 );
b.自己加的路径一定要放在缺省的路径前.因为MVC这鬼东西找路径时是按代码的先后顺序来找的,如果把缺省的放在前面,就会直接匹配,自己定义的路径就匹配不上了.
3)客户端和服务端交互的流程:
发出一个URL请求后,MVC根据设好的route找到处理这个route的方法,就是action,对要显示的界面和数据做些设置后,返回一个View,就是页面:
 public ActionResult Index()
 {
 //ViewData["Message"] = "Welcome to ASP.NET MVC!";

 return View();
 }
这里的View(),就是一个HTML页面.如果没有参数,MVC就去找和方法同名的页面,如在这个例子里,就到Views/Home目录下去找Index.aspx这个文件.如果指定了参数,如return View("mypage");则到Views/MyPage目录下(如果有这个目录的话)找MyPage.aspx,如果没有,再到Home目录下去找MyPage.aspx.这是一种形式.

另外一种形式,如果想设置页面里的某些元素的值,比如设置某个TextBox的值,主要有两种方式:
一种是通过ViewDataDictionary传值:
 public ActionResult Index()
 {
 //ViewData["Message"] = "Welcome to ASP.NET MVC!";
 ViewData["txtCode"] = "test";
 return View();
 }

ViewDataDictionary是一个容器,什么都可以往里面放,在客户端取出里面的值,很简单,如上面定义的那个TextBox:
< %= Html.TextBox("txtCode", string.Empty, new {@id="txtCode", style="width:100px"}) %>, 如果把初始值string.Empty改成 ViewData["txtCode"],客户端就会显示出"test".
需要注意的是ViewData是单向传递的,就是说只能从服务端传给客户端.

还有一种方法,是利用Model.Model是一个不可见的在客户端的数据对象.前面提到,MVC的View页面开头有一句:
< %@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>,这里的ViewPage没有指定对应页面的Model对象是什么类型,为了使用方便,可以这样指定Model的数据类型:
< %@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage< MyObjectType>" %>
在上面的Index方法里,加上:

 public ActionResult Index()
 {
 //ViewData["Message"] = "Welcome to ASP.NET MVC!";
 MyObjectType myType = new MyObjectType();
 myType.TxtCode = "test";
 ViewData["txtCode"] = "test";
 return View("Index", myType);
 }


然后将客户端的语句改写成:
< %= Html.TextBox("txtCode", Model.TxtCode, new {@id="txtCode", style="width:100px"}) %>,
也能显示出"test".
更好的做法是:
< %= Html.TextBox("myType.TxtCode", Model.TxtCode, new {@id="txtCode", style="width:100px"}) %>.
服务端向客户端传数据,主要就用ViewData和Model这两种形式.

至于客户端向服务端发数据就比较简单,就是通过submit表单,如上面的例子,服务端用Request["txtCode"]或者Request.Form["txtCode"]来取值.
如果用上面最后一种写法,前台的HTML元素和Model已经完全绑定起来,直接取myType.TxtCode就可以了.

5.客户端和服务端的绑定
客户端实际上是先生成一个Model对象的实例,给它的属性赋好值,然后再发到服务端.那么各种HTML元素是如何与服务端绑定起来呢?
最简单的是TextBox,服务端定义一个string类型的属性(property),客户端用modeltype.property的形式就绑定起来了,如上面的例子.
CheckBox也类似,先在服务端定义一个boolean类型的属性:
public class MyModelType
{
 public bool IsChecked
 {
 get; set;
 }
}
客户端:
< %= Html.CheckBox("myType.IsChecked",Model.IsChecked) %>
麻烦一点的是radioButton,服务端要定义一个enum类型,一个该类型的属性,一个bool类型的属性:
public class MyModelType
{
 public enum EnumCheck
 {
 Yes,
 No
 }
}
 public EnumCheck CheckIndicator
 {
 get; set;
 }
 public bool IsYesChecked
 {
 get; set;
 }
客户端:
< %= Html.RadioButton("myType.CheckIndicator", "Yes", Model.IsYesChecked) %>
< %= Html.RadioButton("myType.CheckIndicator", "No", !Modle.IsYesChecked) %>
这里定义一个IsYesChecked,主要是为了初始radioButton的状态.
客户端提交表单后,服务端可以这样检查哪个radiobutton被选中:
if (myType.CheckIndicator == MyModelType.EnumCheck.Yes)
{//选中了Yes
}

最麻烦的是dropdownlist,在服务端:
public class MyModelType
{
 public SelectList MyDropDown
 {
 get; set;
 }
}

 public ActionResult Index()
 {
 MyModelType myType = new MyModelType();
 List list = new List();
 list.Add(new SelectListItem{Text = "test1", Value = "value1"});
 list.Add(new SelectListItem{Text = "test2", Value = "value2"});
 list.Add(new SelectListItem{Text = "test3", Value = "value3"});
 myType.MyDropDown = new SelectList(list, "Value", "Text", list[0].Value);//最后一个参数是指定dropDownList中被选中的值
 return View("Index", myType);
 }
在客户端:
< %= Html.DropDownList("dpl", Model.MyDropDown) %>
这里,好象不能用 < %= Html.DropDownList("myType.MyDropDown", Model.MyDropDown) %>,否则递交表单时会提示SelectList没有无参数的构造方法的错误.

6.其他体会:
目前还没有用到Grid,感觉可能用MVC来做比较麻烦,和GridView不可同日而语.
JQuery,Linq to SQL等新鲜玩意还没有尝试.
感觉这个东西最大的不足就是客户端还缺少好用的控件支持,HtmlHelper实在太简陋,比如连个calendar控件都没有.
Javascript有了更多的施展余地.确实很多简单的功能没必要postback到服务端,影响性能.
搞MVC这个鬼东西,需要对HTML有更深入的了解.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: