asp.net MVC与RAILS3的比较
进入后Web年代之后,MVC框架进入了快速演化的时代,Struts等垂垂老矣的老一代MVC框架因为开发效率低下而逐渐被抛弃,新一代的MVC则高举敏捷的大旗,逐渐占领市场,其中的代表有Rails (ruby), .NET MVC (.NET), Django (Python),Symfony (php)等等,这些框架的思想都大同小异,这里列举出Rails3和.NET MVC的一些的区别,以方便Web开发者从Rails迁移到.NET MVC,或者反之,从.NET MVC迁移到Rails.生成项目Rails和.NET MVC都能够产生项目的基本骨架,只是生成的方式略有不同,Rails采用的是命令行的方式:
java代码- railstapir
而Microsoft则秉承其强大的IDE,提供了项目向导。最终得到的目录结构,仅在测试和配置项上略有不同。
Rails | ASP.NET MVC |
/app/models | /Models |
/app/controllers | /Controllers |
/app/views | /Views |
/public/javascript | /Scripts |
/public | /Content |
/db | /App_Data |
/test | 单独的VS项目 |
/config | /Global.asax, /PRoperties, Web.config |
值得一提的是rails的一个亮点:rails可以预先配置三个不同的环境:开发、测试、最终产品,可以通过RAILS_ENV这个环境变量来做简单切换,.NET MVC并未提供这样的配置环境,你可以通过手工配置来完成。模型ModelRails默认采用ActiveRecord作为模型,当然切换到其他的框架也很简单,可选项有 Neo4J, MongoDB,和DataMapper。在Rails中,还是采用命令行来创建模型,Rails会生成一些骨架代码,包括:模型、迁移任务和测试。你可以用-o来选择其他模型、-t来选择其他测试框架:
Java代码- $railsgmodelcustomername:stringemail:string
- invokeactive_record
- createdb/migrate/20100419094010_create_customers.rb
- createapp/models/customer.rb
- invoketest_unit
- createtest/unit/customer_test.rb
- createtest/fixtures/customers.yml
Rails默认采用Sqlite3作为后台数据库,而且Rails会很贴心的为开发、测试、生产三个环境分别产生一个数据库拷贝。在Rails中,所有的数据库的操作都通过脚本和迁移来完成,Rails中的迁移应该是最有价值的一个东西,当不同的开发者同时在修改一个数据库,或者您在升级现有的生产环境下的数据库,迁移就显示出它的强大威力:
Java代码- classCreateCustomers<ActiveRecord::Migration
- #Calledwhenmigratinguptothisversion
- defself.up
- create_table:customersdo|t|
- t.string:name
- t.string:email
- t.timestamps
- end
- end
- #Calledwhenmigratingdownfromthisversion
- defself.down
- drop_table:customers
- end
- end
我们可以通过rake db:migrate命令迁移到不同的数据库版本上去。和Rails不同的是,.NET MVC并为绑定一个模型框架,你要从既有的框架中选择一个适合你的,这个名单里可以用Nhibernate,Linq to SQL, Entity Framework,Castle ActiveRecord或者Ruby的ActiveRecord,不过.NET MVC没有迁移的概念,这有点遗憾。大部分情况下Linq To SQL就很适合项目开发。查询语言Rails3使用AREL(Active Record Relations),LINQ-to-SQL则使用LINQ。 二者都是相当优美的语言
Java代码- #AsimplequerywithAREL
- User.where(users[:name].eq('Anders')).order('users.idDESC').limit(20)
Java代码- //ThesamewithC#
- //LambdaSyntax
- db.Users.where(u=>u.Name=="Anders").orderBy(u=>u.Id).Take(20)
- //LINQSyntax
- (fromuindb.Users
- whereu.Name=="Anders"
- orderbyu.Iddescending
- selectu).Take(20);
现在除了在.NET中采用Ruby的ActiveRecord(借助ironruby),目前还没有其他框架提供类似Ruby的findbyXXX的功能,不过C# 4.0的method_missing使得这类框架应该会很快出现(比如Nhibernate 3.0)控制器在.NET MVC中,你在Controller目录上点添加,就有很贴心的向导引导你为项目添加控制器,甚至还可以增加基本的CRUD的功能。
Java代码- publicclassCustomersController:Controller{
- //GET:/Customers/
- publicActionResultIndex(){
- returnView();
- }
- //GET:/Customers/Details/5
- publicActionResultDetails(intid){
- returnView();
- }
- //GET:/Customers/Create
- publicActionResultCreate(){
- returnView();
- }
- //POST:/Customers/Create
- [HttpPost]
- publicActionResultCreate(FormCollectioncollection){
- try{
- //TODO:Addinsertlogichere
- returnRedirectToAction("Index");
- }catch{
- returnView();
- }
- }
- }
和Rails的脚手架代码一样,这些最基本的代码99%会被废弃,但是提供了“让程序跑起来看看”的基础。Rails还是通过命令行来为项目增加控制器,你还可以在命令行里制定为控制器生成哪些Action。过滤器Rails很容易为某个Action添加个过滤器
Java代码- classItemsController<applicationController
- before_filter:require_user_admin,:only=>[:destroy,:update]
- before_filter:require_user,:only=>[:new,:create]
- end
.NET也不含糊,只要重载OnActionExecuting就可以实现同样的功能:
Java代码- overridevoidOnActionExecuting(ActionExecutingContextfilterContext)
- {
- varaction=filterContext.ActionDescriptor.ActionName;
- if(newList<string>{"Delete","Edit"}.Contains(action)){
- RequireUserAdmin();
- }
- if("Create".Equals(action)){
- RequireUserAdmin();
- }
- }
或者通过.NET的attribute更漂亮的完成
Java代码- [RequireUserAdmin("Delete","Edit")]
- [RequireUser("Create")]
- publicclassCustomersController:Controller
路由在Rails中,可以修改routes.rb来修改路由,默认的Rails的路由被配置成RESTful:
Java代码- Tapir::Application.routes.drawdo|map|
- resources:animals
- get"customer/index"
- get"customer/create"
- match"/:year(/:month(/:day))"=>"info#about",
- :constraints=>{:year=>//d{4}/,
- :month=>//d{2}/,
- :day=>//d{2}/}
- match"/secret"=>"info#about",
- :constraints=>{:user_agent=>/Firefox/}
- end
通过rake routes你可以快速查看路由的结果。ASP.NET MVC的路由稍微复杂一些,不过同样强大:
Java代码- //Global.asax.cs
- publicclassMvcApplication:System.Web.HttpApplication{
- publicstaticvoidRegisterRoutes(RouteCollectionroutes){
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- //Constrainedroute
- routes.MapRoute("Product","Product/{productId}",
- new{controller="Product",action="Details"},
- new{productId=@"/d+"});//Constraint
- //Routewithcustomconstraint,definedbelow
- routes.MapRoute("Admin","Admin/{action}",
- new{controller="Admin"},
- new{isLocal=newLocalhostConstraint()});
- }
- ...
- }
- publicclassLocalhostConstraint:IRouteConstraint{
- publicboolMatch(HttpContextBasehttpContext,Routeroute,
- stringparameterName,RouteValueDictionaryvalues,
- RouteDirectionrouteDirection)
- {
- returnhttpContext.Request.IsLocal;
- }
- }
View二者在View上的表现十分接近,添加控制器的时候,会自动创建相应的视图,规则也类似:视图所在的文件夹以控制器的名字命名,视图的文件名则以控制器的action命令,二者也都提供了从某个模型创建脚手架视图的能力。PartialsRails和Asp.NET MVC都提供了在文件中包含部分HTML文件能力,ASP.NET MVC的文件采用ASP,而Rails默认是ERB或HAML.
Java代码- <!--Rails-->
- <%=render'form'%>
Java代码- <!--ASP.NETMVC-->
- <%Html.RenderPartial("Form",Model);%>
.NET MVC 2中更做出了一些改进,提倡用2个替代的方法来产生代码:
Java代码- <%=DisplayFor("Address",m=>m.Address)%>
- <%=Edit