MVC索引页

 ASP.NET MVC Framework 系列

序言

做为设计模式的王者,MVC在众多领域都成为良好的模型的代名词,从前在ASP.NET下我们只能依靠Monorail来实现ASP.NET下无控件的MVC,但是现在ASP.NET 下的MVC已经成为现实。
本文只想让大家更直观地认知ASP.NET MVC,如果语言有所不当,还望大家海涵。当然,如果文中有所纰漏还希望大家及时指出,我也好做及时的修改。
在下本着对初学者负责的态度来书写本系列中的各篇文章,但期间的恒心与毅力相信过来的人更加明白,所以如果书写有误希望大家谅解。

ASP.NET MVC 正式版相关信息

ASP.NET MVC曾经是ASP.NET 3.5 Extensions Preview 的一个部分.如今历经五个Preview一个Beta两个RC版本终于走向我们。

最新版本:ASP.NET MVC正式版1.0

  1. 安装包: ASP.NET MVC RTM release
  2. 源代码及特性程序集:ASP.NET MVC v1.0 Source
  3. 文档:ASP.NET MVC MSDN 文档
  4. 博客园专题:ASP.NET MVC专题

文章编写约定

  1. 本文的前提环境为.NET 3.5,但笔者会尽力写在.NET2.0 SP1下兼容的程序
  2. 文本中所使用的IDE都为Visual Studio 2008(中文) 语言基本为C#不过为了方便大家理解 ,也可能会有一些Visual Basic
  3. 笔者计算机操作系统为Windows 2003 std/Windows Vista/Windows 7
  4. 其它约定笔者将会后续补充

交互与问答

视频:ASP.NET MVC 入门视频教程

QA:ASP.NET MVC问题索引

ASP.NET MVC 系列文章

 

以下文章属于ASP.NET MVC 1.0 正式版

以下文章属于ASP.NET MVC 1.0 RC

以下文章属于ASP.NET MVC 1.0 Beta

以下文章属于Asp.net Mvc CodePlex Preview 5


以下文章属于Asp.net Mvc CodePlex Preview 4

以下文章是属于Asp.net MVC preview 3

以下文章是属于Asp.net MVC preview 2

我的一些ASP.NET MVC的开源项目

  1. ASP.NET MVC File Management(文件管理)
  2. CHMVCMS(内容管理系统)
  3. CHOJ#(在线编译评判)
  4. ASP.NET MVC Ajax(Ajax操作)
  5. CHSNS#(SNS开源项目)
  6. Infancy (A Forum Application)(ASP.NET MVC论坛)
  7. WebAsk(类似百度知道的问答系统)

相关站点

 

 

ASP.NET技术




posted @  2011-01-23 23:24 P_Chou 阅读(2528) |  评论 (3)  编辑

posted @  2011-01-07 23:07 P_Chou 阅读(2334) |  评论 (2)  编辑


posted @  2010-12-07 08:27 P_Chou 阅读(3175) |  评论 (15)  编辑

posted @  2010-12-01 22:28 P_Chou 阅读(2924) |  评论 (12)  编辑

posted @  2010-11-26 22:45 P_Chou 阅读(3003) |  评论 (9)  编辑

posted @  2010-11-20 17:45 P_Chou 阅读(3411) |  评论 (4)  编辑

posted @  2010-11-15 22:47 P_Chou 阅读(4799) |  评论 (11)  编辑

posted @  2010-11-08 21:00 P_Chou 阅读(8422) |  评论 (4)  编辑

posted @  2010-11-02 18:03 P_Chou 阅读(5426) |  评论 (13)  编辑

posted @  2010-11-01 20:58 P_Chou 阅读(6404) |  评论 (10)  编辑


posted @  2010-10-19 22:28 P_Chou 阅读(3358) |  评论 (25)  编辑

 

 

===================

 

 

 被称为一个漂亮的Asp.net MVC应用,从代码角度来看,我认为得满足这三点:

1. 使用依赖注入框架。

2. 不要直接依赖Cache, HttpContext等。

3. View中不要条件逻辑。

  当然不只是这三点,还有很多。我个人拿它们出来,是认为这些很重要但是经常被忽视。

 

  对于第1点,优点在于松耦合,可测试性很好。如果在Controller里面想要使用某些Service,要么new出来,要么用单例的形式,如UserService.Instance,这样想对Controller写单元测试都不容易,它和这些Service耦合太紧密,无法将这些Service替换成Stub实现。因此,松耦合是必须的。要实现这个功能,必须让依赖注入框架来创建Controller,才有可能注入依赖并组装对象。MVC里面有一个ControllerFactory的东西,可以使用来达到这个目的。

  a. 写一个类,继承自DefaultControllerFactory,例如 UnityControllerFactory : DefaultControllerFactory

  b. 覆盖方法GetControllerInstance,使用依赖注入框架来创建Conroller

  c. 修改Global.asax.cs, 在Application_Start内注册使用自己的ControllerFactory,

     ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory())

  d. 对Controller进行构造函数注入,例如:

      public class UserController : Controller

      {

           public UserController(IUserService, userService, IMessageService messageService)

           …

       }

    从现在开始,所有的Controller都是通过依赖注入框架来创建的,新增的Service就在依赖注入框架里面注册,Controller要使用哪些Service就往构造函数里加,反正框架会注入进来。

 

    第2点, 类如HttpContext.Current.Session[“xxx”] = …, HttpContext.Current.Cache.Insert…此样的代码充斥在各个角落。有问题吗?还是老问题,可测试性,可替换性。

    像HttpContext这种东西,几乎是不能Mock或者Stub的,只要代码中使用了HttpContext,可以说它就没法做单元测试。为什么很多人都会这么用呢,一个原因是图方便图简单,二是没有写单元测试。要用Session直接用就好了,封装一下再用多麻烦啊,这就是图简单。

    解法很简单,对HttpContext进行封装,例如ISessionProvider, ICacheProvider,然后通过依赖注入框架,注入到Controller中去,这样的结果是代码可测试性高,而且想改变Cache机制也很方便。

    意识不够。什么意识?让代码松耦合的意识。使用静态方法,静态变量,直接new依赖的对象,这些都是松耦合的反例。我们写代码的时候要规避它们。即使我们不用TDD(极端一点来说,现在不写单元测试),脑子里也要清楚记得,面向对象的法则、松耦合的一些原则等等,然后反应到代码上去。

 

 (推荐)asp.net mvc强大的分页控件MvcPager

posted @  2010-05-03 16:18 longgel 阅读(8515) |  评论 (40)  编辑

 

 

 

继我的Ajax服务端框架完成后, 也花了些时间学习了一Asp.net MVC,感觉我的Ajax框架也能玩MVC开发, 于是乎,在又加了点功能后,现在也能像Asp.net MVC那样写aspx和ascx了。

先来点代码来看看,具体的页面呈现效果请参考: 通用数据访问层及Ajax服务端框架的综合示例,展示与下载

<%@ Page Title="商品管理" Language="C#" MasterPageFile="~/MasterPage.master"       Inherits="FishWebLib.Mvc.MyPageView<ProductsPageData, ProductsModelLoader>" %>  <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">     <script type="text/javascript" src="/js/MyPage/Products.js"></script> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">  <table cellpadding="4" border="0"> <tr><td>当前分类</td><td>         <select id="ddlCurrentCategory" onchange="<%= UiHelper.DropDownListAutoRedir("ddlCurrentCategory")%>"           combobox="not-editable" style="width:300px;"> <%= Model.Categories.ToHtmlOptions("categoryId", false, "searchWord", "page")%> </select>     </td><td>         <a id="btnCreateItem" href="#" class="easyui-linkbutton" iconCls="icon-add">添加商品</a>     </td></tr> </table> <div style="height: 10px"></div>   <table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse;">     <tr align="left">         <th style="width:20px;">&nbsp;</th>         <th style="width:550px;">商品名称</th>         <th style="width:120px;">单位</th>         <th style="width:120px;">单价</th>         <th style="width:50px;">数量</th>     </tr> <% foreach( Product product in Model.Products ) { %>     <tr>         <td><a href="/AjaxProduct.Delete.cs?id=<%= product.ProductID %>&returnUrl=<%= this.CurrentRequestRawUrl %>"          title="删除" class="easyui-linkbutton" plain="true">             <img src="/Images/delete.gif" alt="删除" /></a>         </td>         <td style="white-space:nowrap;">             <a href="#" rowId="<%= product.ProductID %>" class="easyui-linkbutton" plain="true" iconCls="icon-open" >                 <%= product.ProductName.HtmlEncode()%></a>         </td><td>             <span name="Unit"><%= product.Unit.HtmlEncode() %></span>         </td><td>             <span name="UnitPrice"><%= product.UnitPrice.ToText() %></span>         </td><td>             <input type="text" pid="<%= product.ProductID %>" value="<%= product.Quantity %>" class="quantityTextbox" />         </td>     </tr> <% } %>  <%= Model.PagingInfo.PaginationBar(5)%> </table>  <input type="hidden" id="hfCurrentCategoryId" value="<%= Model.CurrentCategoryId %>" />   <div id="divProductInfo" title="商品" style="display: none"><div style="padding: 8px"> <fish:ProductInfo ID="ProductInfo1" runat="server" ModelDataName="Model.ProductInfoViewData" /> </div></div>  </asp:Content>   

再来个ascx

<%@ Control Language="C#" Inherits="FishWebLib.Mvc.MyUserControlView<OrderListViewData>" %>  <table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse; width: 99%">     <tr align="left">         <th style="width:100px;">订单编号</th>         <th style="width:160px;">时间</th>         <th style="width:300px;">客户</th>         <th style="width:100px;">订单金额</th>         <th style="width:60px;">已处理</th>     </tr> <% foreach( var item in Model.List ) { %> <tr>     <td>         <a href="#" OrderNo="<%= item.OrderID %>" class="easyui-linkbutton" plain="true" iconCls="icon-open">         <%= item.OrderNo %></a>     </td>     <td><%= string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.OrderDate) %></td>     <td>         <a href="#" Customer='<%= item.ValidCustomerId %>' class="easyui-linkbutton" plain="true" iconCls="icon-open">         <%= item.CustomerName.HtmlEncode() %></a>     </td>     <td><%= item.SumMoney.ToText() %></td>     <td>         <%= item.Finished.ToCheckBox(null, "chk_Finished", true) %>     </td> </tr> <% } %>  <%= Model.PagingInfo.PaginationBar(5) %> </table>   

与Asp.net MVC的aspx,ascx一样:没有与之对应的CodeFile

再来看看"商品管理"页面加载数据的C#代码吧。注意类型的名称与方法的签名,它们在上面Page指令中有引用。

public class ProductsModelLoader {     public static ProductsPageData LoadModel()     {         ProductsPageData result = new ProductsPageData();         result = new ProductsPageData();         result.Categories = BllFactory.GetCategoryBLL().GetList();          if( result.Categories.Count == 0 ) {             //HttpContext.Current.Response.Redirect("/Categories.aspx", true);    // 不建议使用这个方法,不利于测试             FishWebLib.HttpContextHelper.RequireRedirect("/Categories.aspx");             return null;         }          // 获取当前用户选择的商品分类ID         result.CurrentCategoryId = FishWebLib.FishUrlHelper.GetIntegerFromQueryString("categoryId", 0);         if( result.CurrentCategoryId == 0 )             result.CurrentCategoryId = result.Categories[0].CategoryID;          result.ProductInfoViewData = new ProductInfoViewData(result.Categories,  					new Product { CategoryID = result.CurrentCategoryId });          result.PagingInfo.PageIndex = result.PagingInfo.GetPageIndex();         result.PagingInfo.PageSize = AppHelper.DefaultPageSize;          // 加载商品列表,并显示         result.Products = BllFactory.GetProductBLL().GetProductByCategoryId(result.CurrentCategoryId, result.PagingInfo);         return result;     } }   public class ProductsPageData {     public PagingInfo PagingInfo;     public List<Category> Categories;     public int CurrentCategoryId;     public List<Product> Products;      public ProductInfoViewData ProductInfoViewData { get; set; }       public ProductsPageData()     {         this.PagingInfo = new PagingInfo();     } } 

上面那个ascx是供JS调用的,C#的实现代码如下:(注意是如何执行用户控件的)

/// <summary> /// 搜索订单,并以HTML代码的形式返回给客户端 /// </summary> /// <returns></returns> public static string Search() {     // 从查询字符串中读取客户端发过的日期范围。     QueryDateRange range = QueryDateRange.GetDateRangeFromQueryString("StartDate", "EndDate");      OrderListViewData data = new OrderListViewData();     data.PagingInfo.PageIndex = data.PagingInfo.GetPageIndex();     data.PagingInfo.PageSize = AppHelper.DefaultPageSize;      // 搜索数据库     data.List = BllFactory.GetOrderBLL().Search(range, data.PagingInfo);      // 执行用户控件,并传递所需的呈现数据。     return FishWebLib.Ajax.UcExecutor.Execute("~/Controls/OrderList.ascx", data); }  public class OrderListViewData {     public List<OrderItem> List;     public PagingInfo PagingInfo = new PagingInfo(); } 

与Asp.net MVC框架一样,页面数据的加载和呈现彻底地分开了。

JS调用上面那个ascx的代码如下:

function btnQuery_Click(){     var dateRange = GetDateRange("txtStartDate", "txtEndDate");     if( dateRange == null ) return false;     var url = '/AjaxOrder.Search.cs?'  				+ $.param({StartDate: dateRange.StartDate, EndDate: dateRange.EndDate});     ShowPickerPage(url, 'divResultList_inner', ShowResultSuccess);     return false; } 

代码回顾

学过Asp.net MVC的朋友应该能发现,前面示例代码中的 aspx, ascx的写法,与Asp.net MVC的写法是100%的兼容的。 但我肯定没有使用Asp.net MVC,您可以下载示例代码去看。

当初学习Asp.net MVC是因为有些人把Asp.net MVC说得太过于神话了,好像用Asp.net做开发,非它不可。但是,学了之后才发现, 确实,这个东西有很多优点,但没那么神奇。我认它最出色的地方还是在于它的思想:MVC,这种思想能够让我们在开发时, 尽量去分离一些可分离的东西,比如:呈现与获取数据的过程,从而可以在一个地方只关注一件事情,也就是它所提倡的:分离关注点。

正如前面所说,我认为Asp.net MVC的优点在于它的设计体现了MVC的思想。但让人不解的是:微软在实现时,不知为何, 非要把MVC搞得与WebForms差别巨大。这种区别尤其是在加入了Route和一堆Html扩展之后。 对于Route和一堆Html扩展,我对它们没多大的兴趣,因为它们于MVC无关,对于代码的维护和性能根本没什么改善。 所以也不打算在这个山寨版本上采用,反而认为现在的代码更容易理解了。

至于在Ajax方面的实现,我的框架也完全是符合MVC思想的。 而且在生成HTML片段时,仍然可以使用MVC的思想:先准备数据,然后交给ascx来呈现。

我的MVC框架与Asp.net MVC的不同之处:
1. 简单了很多,抛弃了许多与MVC无关的东西。因此,学习成本更低。
2. Controller少了很多限制,可以在单独的类库中实现。为了方便安全检查,建议放在一个命名空间中,或者取个前缀或后缀,这也符合:约定胜于配置。
3. 由于没有Route,页面是由Asp.net框架所调用的,而不是先经过Controller,但页面的数据加载是由一个辅助的类来完成的, 这个类一定要实现一个名为“LoadModel”的方法(签名不限,框架会识别),同样,也是采用约定胜于配置的原则。

点击此处进入下载页面

 

 

 

 

 Asp.net MVC2.0系列文章-编辑和删除新闻操作

摘要: 上一篇文章,我们简单地完成了新闻内容的展示功能(Asp.net MVC2.0系列文章-显示列表和详细页面操作),此篇文章,我们使用Asp.net MVC2.0实现新闻记录的编辑和删除功能。 阅读全文
posted @  2010-07-01 00:05 灵动生活 阅读(4489) |  评论 (13)  编辑
摘要: 上一篇文章,我们简单地完成了新闻的添加操作(Asp.net MVC2.0系列文章-添加操作)此篇文章,我们使用Asp.net MVC2.0实现新闻清单的展示和新闻详细页面。 阅读全文
posted @  2010-06-28 00:03 灵动生活 阅读(6359) |  评论 (13)  编辑
摘要: 此篇文章,我们将实现MVC2.0的添加操作,主要包括Model的创建、View的Edit操作和Control的Create操作。 阅读全文
posted @  2010-06-24 00:19 灵动生活 阅读(10764) |  评论 (31)  编辑
摘要: 此篇文章只是让初学者对 MVC2.0网站有个大概的印象,学习和创建MVC2.0网站应用程序并不是想象的那么苦难,不妨动手试一试 阅读全文
posted @  2010-06-23 00:01 灵动生活 阅读(6718) |  评论 (13)  编辑
摘要:  MVC索引页ASP.NET MVC Framework是微软在ASP.NET中所添加的一组类别库,这组类库可以使用Model-View-Controller的设计模式来开发ASP.NET的应用程序  阅读全文

 

 

 

 通过问题学习asp.net mvc局部处理流程

摘要: 很基础,但好多人都不一定关注的问题 阅读全文
posted @  2011-10-09 16:43 姜敏 阅读(1187) |  评论 (2)  编辑
Mongodb官方驱动的进一步包装
摘要: 无论是samus驱动还是官方驱动,其实功能都各有秋千,samus驱动对数据操作进行了Linq封装,即我们在操作List时,完全可以采用类似Linq一样的语法,这样可以使我们的学习成本降低,官方驱动的特点是针对数据处理有返回值。我们的需求是即需要操作返回值也需要Linq封装,于时我找到了老赵写的easyMongo,但在它的基本上做了一小部分取舍 阅读全文
posted @  2011-08-27 08:32 姜敏 阅读(1632) |  评论 (12)  编辑
Codematic的mysqlhelper问题
摘要: Codematic,我想有一部分朋友应该用过,我最近使用CodematicDemoS3这个项目中的mysql数据库帮助类,但发现在处理数据库连接以及异常上有比较明显的错误,不知道是我下载的这个版本问题还是Codematic一直都这么写数据库操作类。 阅读全文
posted @  2011-04-01 12:51 姜敏 阅读(1375) |  评论 (7)  编辑
项目经验总结(二)项目开发前开发人员需要做什么
摘要: 这篇主要来总结下做为一个开发人员,在项目真正进入代码开发期间,开发人员都需要做哪些准备工作。  阅读全文
posted @  2010-11-03 12:29 姜敏 阅读(2761) |  评论 (4)  编辑
项目经验总结(一)如何约定接口的定义
摘要: 谈谈和其它小组合作开发项目时,如何约定服务接口。  阅读全文
posted @  2010-11-01 20:15 姜敏 阅读(2834) |  评论 (4)  编辑
NorthScale Memcached Server尝试总结(二)
摘要: 上篇文章中我列举了几个关于尝试NorthScale Memcached Server的问题,也有几个朋友在尝试或者在新项目中应用它。这里我就大家的问题再总结下 阅读全文
posted @  2010-08-23 20:56 姜敏 阅读(1543) |  评论 (5)  编辑
NorthScale Memcached Server尝试总结
摘要: 我把我测试中遇到的问题和大家分享下,如果有朋友遇到和我一样的情况,希望能少走些弯路。  阅读全文
posted @  2010-08-18 16:50 姜敏 阅读(1727) |  评论 (13)  编辑
asp.net mvc(十一)自定义view engine
摘要: 很久没有更新mvc的文章了,不过这篇在实际项目中还是非常有用的,例如,我们可以把两个不同的view page指定同一个Controller等等。  阅读全文
posted @  2010-06-30 17:05 姜敏 阅读(1947) |  评论 (4)  编辑
服务的异步调用需要注意的地方
摘要: 服务的异步调用,需要根据当前应用场景来考虑是否采用,而且可以根据客户端对结果的关心程度,适当更改服务的设计来提高系统响应能力。同理,不合理的异步调用,首先会增加客户端程序的复杂性,而且有可能会影响系统性能。  阅读全文
posted @  2010-05-23 13:28 姜敏 阅读(1283) |  评论 (4)  编辑
网站重构之配置文件分解
摘要: 根据应用程序功能点来分解配置文件,达到提高编程效率,准确性的目的。 阅读全文
posted @  2010-05-04 22:09 姜敏 阅读(1685) |  评论 (11)  编辑
asp.net mvc(十)
摘要: OutputCacheAttribute与CompressAttribute 阅读全文
posted @  2010-03-09 21:23 姜敏 阅读(1468) |  评论 (4)  编辑
asp.net mvc系列
摘要: 记录下个人学习asp.net mvc的一些过程:  阅读全文
posted @  2010-03-07 10:15 姜敏 阅读(1909) |  评论 (6)  编辑
asp.net mvc(七)
摘要: System.Web.Mvc.Html和TagBuilder搞定页面控件。  阅读全文
posted @  2009-08-14 15:20 姜敏 阅读(2332) |  评论 (2)  编辑

 

 

 

 

 

 ASP.NET MVC中对Model进行分步验证的解决方法

麒麟 2010-09-27 00:16 阅读:2151 评论:9
麒麟 2010-09-24 21:06 阅读:2684 评论:14
麒麟 2010-08-06 01:08 阅读:4222 评论:10
麒麟 2010-08-04 08:29 阅读:2330 评论:8
麒麟 2010-08-03 18:26 阅读:3177 评论:27
麒麟 2010-08-02 09:45 阅读:1870 评论:16
麒麟 2010-08-01 14:08 阅读:2845 评论:17
麒麟 2010-07-31 13:21 阅读:1975 评论:17
麒麟 2010-07-30 01:14 阅读:3758 评论:33
麒麟 2010-07-28 10:03 阅读:1142 评论:4
麒麟 2010-07-18 19:58 阅读:4932 评论:26

----------------------------------------------

在我们建立Action时,有个原则,就是最好和页面名称相同,如果一个名为Index的Action,

那它的页面就应该是Index.aspx/cshtml,

如果你非要建立一个Index1.aspx,那路由是无法找到的,

当然,如果你想让路由找到,就用return View("Index1")来代替return View()就可以了

 

 

 

-------------------------------------------------------

 

posted @  2010-06-24 15:41 你听海是不是在笑 阅读(2657) |  评论 (10)  编辑
posted @  2009-11-30 14:37 你听海是不是在笑 阅读(610) |  评论 (6)  编辑
posted @  2009-11-27 14:42 你听海是不是在笑 阅读(2261) |  评论 (5)  编辑
posted @  2009-11-26 15:57 你听海是不是在笑 阅读(1725) |  评论 (4)  编辑
posted @  2009-11-24 18:05 你听海是不是在笑 阅读(2195) |  评论 (3)  编辑
摘要: GridView中的分页是用post做的,所以将查询表单中的内容可以存到ViewState中,翻页的时候可以利用,实现起来就比较容易些,而在mvc中这些就要我们自己来做了,Contrib中的分页只能应付简单应用,对于查询后结果的分页没做处理,下面我们来改造一下这个分页程序。 阅读全文
posted @  2009-11-18 14:41 你听海是不是在笑 阅读(2090) |  评论 (4)  编辑
posted @  2009-11-11 11:40 你听海是不是在笑 阅读(3878) |  评论 (8)  编辑
posted @  2009-11-10 15:54 你听海是不是在笑 阅读(1195) |  评论 (3)  编辑
posted @  2009-11-04 18:11 你听海是不是在笑 阅读(1212) |  评论 (0)  编辑
posted @  2009-10-28 15:51 你听海是不是在笑 阅读(1283) |  评论 (0)  编辑
posted @  2009-10-27 11:26 你听海是不是在笑 阅读(1105) |  评论 (3)  编辑
posted @  2009-10-26 16:36 你听海是不是在笑 阅读(1485) |  评论 (2)  编辑

 

当前标签: MVC

xfrog 2011-02-11 16:01 阅读:2436 评论:5
xfrog 2011-01-25 19:57 阅读:2175 评论:3
xfrog 2011-01-16 15:21 阅读:1949 评论:2
xfrog 2011-01-10 20:01 阅读:2062 评论:5
xfrog 2011-01-06 22:08 阅读:1985 评论:3
xfrog 2011-01-01 16:38 阅读:1715 评论:4
xfrog 2010-12-29 21:51 阅读:2340 评论:3
xfrog 2010-12-25 16:02 阅读:2043 评论:3
xfrog 2010-12-19 11:34 阅读:2350 评论:7
xfrog 2010-12-12 19:16 阅读:2293 评论:7

你可能感兴趣的:(mvc)