分类
原创作品 技术

Ruby/RoR on IIS6.1 via IronRuby and .NET3.5

标题足够明了了。

Ruby是个好东西。第一次接触Ruby的语法,就被它的简洁和动态特征吸引了。RoR (Ruby on Rails) 具体有多好我倒不是很关心,对我来说Ruby的意义更在于扩展了server-side的语言和技术体系。

市面上主流的web开发技术确实很多。自己的工作内容是J2EE,但业余兴趣也做这个就有些枯燥了;我对ASP.NET情有独钟,无奈其升级换代太快,技术体系也偏庞大;PHP一直没有机会深入学习,一直觉得它的语法不够清爽。

在给定browser端的技术方案是Flex、Ajax或者HTML5的前提下,其实server端是什么技术区别也不会太大。如果这个技术从语言层面即可以面向对象又有足够动态特性,从框架层面可以保持轻量又足够灵活,那就是一个优秀的选择。Ruby上基于Rack有Sinatra可以轻松编写RESTful Service,目前对我已足够了。

跨平台是我选Ruby的另一个理由。这里所说的跨平台是指可以在多种虚拟机上运行。已知的有可以运行在Java虚拟机上的JRuby,和运行在.NET虚拟机上的IronRuby。这对我来说意味着在纯Ruby环境下开发的应用可以很轻松的迁移到Java平台或者.NET平台。或者再说明白一点,国内还没见到比较靠谱的Ruby虚拟主机服务商,而.NET在国内则满地都是,还便宜,而且什么时候Java主机大众化了,我还可以把应用迁移过去。

回到方案。要点是DIY编译一下IronRuby.Rack。基本过程参考如下视频即可:
http://www.iamnotmyself.com/2010/04/22/RunningRailsInIIS7WithIronRubyRack.aspx

我的开发编译环境比较老,但经过反复尝试也成功部署了。

1、下载并安装IronRuby。http://www.ironruby.net/Download ,我下载了其中1.0 for .NET2.0(据说for .NET4.0的版本会更快)的Windows Installer,这个发行版本内置了Ruby 1.8及其周边。安装至C:\IronRuby\,安装程序会帮我把环境变量之类的设置好。

2、在Ruby上安装Rack、数据库和RoR。 参考http://www.ironruby.net/Documentation/Real_Ruby_Applications/Rails

  • Rack和Rails,在命令行里执行:
    > igem install rake rails --no-rdoc --no-ri
    Successfully installed rake-0.8.7
    Successfully installed activesupport-2.3.5
    Successfully installed activerecord-2.3.5
    Successfully installed rack-1.0.1
    Successfully installed actionpack-2.3.5
    Successfully installed actionmailer-2.3.5
    Successfully installed activeresource-2.3.5
    Successfully installed rails-2.3.5
    8 gems installed
  • 数据库选了SQLite3:
    > ir -S gem install sqlite3-ironruby --no-ri --no-rdoc
    Successfully installed sqlite3-ironruby-0.1.1
  • 随便建个目录,然后自动生成RoR的应用:
    > ir -S rails IronRubyOnRails
          create
          create  app/controllers
          create  app/helpers
          create  app/models
          create  app/views/layouts
          create  config/environments
          create  config/initializers
          ......
  • 利用内置Web服务器测试RoR,http://localhost:3000 能正常显示页面即成功:
    > cd IronRubyOnRails
    > ir script\server
    => Booting WEBrick
    => Rails 2.3.5 application starting on http://0.0.0.0:3000
    => Call with -d to detach
    => Ctrl-C to shutdown server
    [2009-04-22 13:55:50] INFO  WEBrick 1.3.1
    [2009-04-22 13:55:50] INFO  ruby 1.8.6 (2009-03-31) [i386-mswin32]
    [2009-04-22 13:55:50] INFO  WEBrick::HTTPServer#start: pid=10848 port=3000

3、下载IronRuby的源代码。http://github.com/ironruby/ironruby/ ,v1.0-rtm或者稍新点的都可以,没有Git直接下载zip包也可以。老实说只会用到其中ironruby/Hosts/IronRuby.Rack目录下的内容。

4、启动Visual Studio 2008(我用的是Visual Web Developer Express 2008),把刚才源代码中ironruby/Hosts/IronRuby.Rack中的IronRuby.Rack.sln作为解决方案打开,会报几个错,不过没关系。

5、查看各项目的属性,检查编译.NET版本是否是3.5。从IronRuby的安装路径中找到以下DLL库,然后添加到IronRuby.Rack工程的引用中。

IronRuby.dll
IronRuby.Libraries.dll
IronRuby.Libraries.Yaml.dll
Microsoft.Dynamic.dll
Microsoft.Scripting.Core.dll
Microsoft.Scripting.Debugging.dll
Microsoft.Scripting.dll
Microsoft.Scripting.ExtensionAttribute.dll

 

6、修改各web项目的web.config。以IronRuby.Rack.Example为例,修改LibraryPaths和GemPath值,把原路径都改到IronRuby的安装路径里去。

7、给IronRuby的安装目录加入NETWORK SERVICE用户组的可读权限,然后在IDE环境中运行IronRuby.Rack.Example(或者IronRuby.Rails.Example)。如果目标IIS版本低于7,如Window Server 2003的IIS6.1,则需要修改浏览器URL来让请求通过ASP.NET处理,如加入后缀.aspx或者.ashx。当然也可以调整IIS的配置使得ASP.NET引擎处理所有请求。结果类似下图即为通过。

ironruby_on_iis

8、部署至远程IIS。需要编译一个发行版的IronRuby.Rack.dll,把IronRuby.Rack项目的生成方式改为release,再生成一次即可。注意这里的目标runtime是.NET3.5,如果用.NET2.0的话编译是很难通过的。把第5步中的所有DLL与这个DLL一起拷贝到远程IIS虚拟目录的bin目录下。

本机编译的发行版本(.NET3.5) IronRuby.Rack

9、上传IronRuby安装路径中的Lib目录至同一远程IIS虚拟目录中。调整web.config第6步中的路径,然后与config.ru、app.rb一起上传至同一目录。

10、浏览器中按第7步的方式测试。第一次加载很慢,以后就快很多了。URL要加后缀这点非常麻烦,部署在Windows Server 2008 + IIS7上应该可以解决(理论上就可以用for .NET4.0的方案了)。

欢迎来到Ruby的世界。

分类
English 技术

Call for vote on turning off Voice Dialer on Android

用Milestone上的更新程序升级到了Android 2.1。系统里自带的语音拨号Voice Dialer是个好玩的东西,相信对于驾驶员也是很有用的工具。但我认为它对我而言没有太大用途,反而是个累赘。原因有三:
I’ve got my Milestone updated to Android 2.1 via its update function. The Voice Dialer bound with this version is certainly an interesting tool which could be very useful tool for drivers. However, I think it’s none of use but a burden to me. Reasons as follows:

  • 我不开车,所以用手操作还是很方便的;
    I’m not a driver so that it’s convenient of me to use my finger;
  • 通讯录上以中文名字为主,可惜Voice Dialer不支持中文;
    Most of contacts in my list are Chinese, pity that Voice Dialer don’t support Chinese language yet;
  • 最重要的问题是这个程序会占掉4~5MB甚至更多珍贵的内存,同时也很耗电。
    I found the Voice Dialer process is always consuming at least 5MB of the RAM and up to 30% of the battery.

用Advanced Task Killer之类的工具尝试关闭Voice Dialer进程未果,看来这属于特殊的系统服务。Google一下得知,可以通过root的方式去重命名或删除Voice Dialer。不过这貌似太折腾了,毕竟手机玩家不一定都要当黑客。所以,希望Android开发小组能考虑给这个程序做个开关,方便我们这些不需要Voice Dialer的用户。
I failed to shut down the Voice Dialer process using tools like Advanced Task Killer, seems this is a special system service. According to a quick googling, I found it possible to rename or delete the Voice Dialer application after rooted. I don’t feel this way to be suitable for the mobile funs who have no interest to be hackers. So maybe it’s a good idea to suggest Android developers to add a turn on/off switch to the Voice Dialer application, for the convenience of us users that do not need Voice Dialer.

在这里,我倡议大家去顶这个申请条目,加星标或者跟帖均可:
Here, I call for your help to vote on the Enhancement ticket by either starring or replying.

http://code.google.com/p/android/issues/detail?id=7669

要点是关注度越高的条目,越能引起Android开发人员的注意。
The point is that, only hot tickets may draw developers’ attention.

分类
English 技术

Some comments on my first GAE (Java) trial

Java版Google App Engine试用感想
Some comments on my first GAE (Java) trial

上一篇,发表一些自己的试用感想。

例子应用的架构及实现
Architecture & Implementation of the Previous Example

先看一下自己开发了一个什么样的例子。用图说明。

me.evis.gae.guestbook_architecture

看源代码,me.evis.gae.guestbook、me.evis.gae.guestbook.client和me.evis.gae.guestbook.sever三个包就是为了形成GWT的表现层和逻辑层。而me.evis.gae.guestbook.bo及其子包是为了包装GAE的数据存储服务形成数据层。

就开发过程而言,在装有Google插件的Eclipse上添加新GAE项目时,插件会代为准备好GAE相关的配置和jar包,同时也有GWT的。而创建新模块时,就纯粹是与GWT有关的事情了。在我看来Google为GWT提供的最佳实践是:

  • 在前端弱化HTML的作用,而由后端位于client包里的入口类(Entry Point Class)编写用户界面及相关交互,在运行时Java的入口类会生成Javascript返回给客户端浏览器;
  • 由入口类来调用同一包内的各种服务接口,并处理返回值;
  • 对于client包中服务接口的实现,都放在server包中。

我之所以加入了bo包及其子包,主要还是是为了能更清楚地了解GWT与GAE之间的关系。由Comment DTO/DAO去以JDO方式去调用GAE的数据存储服务,然后再让上边的Comment服务的实现去调用Comment DTO/DAO而不是直接去调GAE的东西。

同时,这样的分离也给了我做单元测试的机会。我为bo包加入了test的子包。JUnit 3的测试用例直接写会出App ID之类的错误,原因是GAE的服务都是云计算,本地调用需要构建一个相应的测试环境,详见Google的官方文档或者是例子应用的源代码。

关于GWT
Comments about GWT

用Java来代替Javascript,有点像写CS的感觉,不过调用服务器端的方法或者使用服务器端的变量都很方便。这种做法确实掩盖了BS和Javascript的复杂性,也有效利用了Java编译所需的严谨性。但是我认为其缺点也是显而易见的:

  • 开发调试用户界面及交互要改Java类,就意味着重新编译,一般也会要求重启服务器,相对来说调试成本较高;
  • 用户界面开发变得不太直观,难以分工。如果所有界面都是Java写出来的,那页面设计师和交互工程师只能轮流给Java程序员端咖啡了。个人觉得如果用GWT,各种页面元素应该还是在HTML上布局好,然后用Java去捕捉那些元素,比如按钮或者区域之类的。

GAE最核心的东西肯定还是数据存储、邮件等这些云计算服务,我想如果有更适合的选择的话,还是没有必要在GWT上投入太多的关注。

关于GAE
Comments about GAE

截止到发文时也只有尝试过数据存储服务而已。关于数据存储服务,Google公布了JDO和JPA两种基于标准的接口。这些现代的数据操作方式大大简化了数据相关的开发,至少不用去数据库里建表了。但GAE是按API调用次数、数据容量、传输大小等因素综合计费的,所以开发时也必须要注意多方面的调优,个人预测Appspot上也许会有不少程序会因为API调用次数和CPU占用时间两项而额外付费。

关于Google的Eclipse插件
Comments about Google Plug-in for Eclipse

  • 装完插件就不要挪动Eclipse了,不然要改好几个配置文件;
  • GWT的Java Editor有时会有些bug导致无法进行语法加亮;
  • GAE的插件方面有些薄弱。除了新工程和调试用的Jetty服务器外好像没看到针对Google各种云计算服务的更细节的功能。

结语
Conclusion

很兴奋,很有用。有机会也要试试其他的服务,有时间可以给自己写个实用些的程序。

缩写
Abbreviations

  • GAE: Google App Engine
  • GWT: Google Web Toolkit
  • JDO: Java Data Objects
  • DTO: Data Transfer Object
  • DAO: Data Access Object
  • CS: Client-server
  • BS: Browser-server