MonoRail - 生命周期及controller/action/view详解
和传统的asp.net webform相比, MonoRail的生命周期简单多了. 一个web请求所经历的主要步骤如下:
1. MonoRailHttpHandlerFactory接收到请求后, 收集上下文, 创建MonoRailHttpHandler.
2. MonoRailHttpHandler分析请求的url, 创建相应的controller并调用相应的action(实际就是controller里的一个方法), url表示了访问的是哪个controller的哪个action. 默认情况下, 格式是/controller名称/action名称.rails. MonoRailHttpHandler会根据请求的url初始化名称相对应的controller并调用相应的action, 例如, home/index.rail对应HomeControll 如果controller继承自SmartDispatcherController, 还会将action的参数与Request的数据进行绑定.
3. Controller调用ViewEngine的Process方法, 输出html内容.
一个页面的生命周期就这样完成了, 是不是觉得很清爽呢 :)
我们再来看看在自己写的action里要做些什么:
1. 处理业务逻辑.
2. 如果需要向view输出内容的话, 把需要被view引用的对象添加到PropertyBag.
3. 如果需要对view进行选择或控制, 调用适当的和view相关的方法.
同样是这么的简单. server control没了, viewstate没了, postback也没了. 在深入了解了MonoRail之后, 你会发现, 这些东西都不是必须的.
下面给MonoRail的各种概念来个比较详细的解释, 大部分摘自MonoRail参考手册
View
默认每个action都会有一个对应的view. 当使用NVelocityViewEngine的时候, view就是一个NVelocity的模板. view文件布局规则如下
view根目录\Controller名称\action名称.vm
Controller在action执行完后, 将会调用模板引擎输出相应的内容. Velocity模板语法参考请看这里
Controller
Controller是MonoRail的核心. MonoRail有一个名为Controller的抽象类, 应用中所有Controller都要从此继承.
Controller的名称一般以Controller后缀, 而Controller的名称默认是类名去掉Controller后缀. 例如HomeController的名称是Home. 如果不
想要这种命名规则的话, 可以标记ControllerDetailsAttribute去指定名称.
下面是基类Controller的一些常用的成员和特性:
Redirect, 和HttpResponse.Redirect类似:
Redirect( String url )
Redirect( String controller, String action )
Redirect( String area, String controller, String action )
CancelView() 如果不需要处理view, 或者甚至action没有对应的view, 就应该调用它停止view的执行
RenderView, 输出view:
RenderView(String name )
RenderView(String controller, String name )
RenderShareView(String name) :
输出在视图根目录的view. 如果一个view需要被多个controller共用, 就应该放在视图根目录.
RenderText(String name) :
输出一段文本, 实际上等同于Response.Write, 并且调用RenderText后, 原来的view的输出将会被取消.
不要忘了, Response对象还可以照常使用. 在用模板引擎输出一个view的同时, 你也可以通过Response.Write输出一些额外的内容, 例如js.
PropertyBag:
PropertyBag是基类Contorller里的一个简单的IDictionary, 被存放在HttpContext.Current.Item里. 放在PropertyBag里的对象就可以在view里被引用
Flash:
特性和PropertyBag完全一样, 只是语义上的区别, PropertyBag用于给view提供数据, Flash则是用来在Request中存放临时的数据.
Helplers:
NVelocity模板并不像aspx那样可以使用任何.NET语法, 他只允许对特定容器里对象的访问. 如果有需要借助后台的类去对界面显的内容进行处理的话(例如对数字或日期进行格式化), 可以创建对象的实例, 然后添加到Helpers集合里. 例如有一个Fomatter类, 里面有多个用于格式化的方法, 则在action里加上语句:
然后就可以在模板里使用Formatter了.
MonoRail里内置了很多Helper, 例如AjaxHelper, HtmlHelper, ValidationHelper, 在官方的sample中会常见到他们在模板里的使用. 他们是在基类Controller初始化的时候被添加到Helpers集合里的.
在view里引用对象
view要引用到的对象应添加到PropertyBag里. 在NVelocity的模板里, 可以引用以下对象
Context (IRailsEngineContext, 类似HttpContext)
Request
Response
Session
所有Request中的元素
所有Flash中的元素
所有PropertyBag中的元素
数据绑定
这是一个能让你消除大量无聊的代码的特性, 只要controller继承自SmartDispatcherController, MonoRailHttpHandler就会根据querystring和form提交的数据, 寻找最合适的方法的重载, 并且把post的数据绑定到对应的参数. 支持所有的基本类型以及他们的数组, 还有HttpPostedFile. 参考手册上有这样的例子
Name: <input type="text" name="name" /> <br>
Email: <input type="text" name="email" /> <br>
Country:
<select name="country">
<option value="44">England</option>
<option value="55">Brazil</option>
</select>
<br>
<input type="submit" value="Create" />
</form>
这样的form提交后, 对应的action的参数将会被自动绑定
{
public void CreateAccount(String name, String email, int country)
{
// perform your create account logic here ..
Redirect("home", "index");
}
}
假如存在一个Account类, 我们还可以让他直接创建Account的实例并且绑定数据, 作为参数传给action, 只需在参数加上DataBindAttribute:
{
//
}
为了避免html元素id的命名冲突, 还可以通过Prefix属性指定前缀
Name: <input type="text" name="accName" /> <br>
Email: <input type="text" name="accEmail" /> <br>
Country:
<select name="accCountry">
<option value="44">England</option>
<option value="55">Brazil</option>
</select>
<br>
<input type="submit" value="Create" />
</form>
{
//
}
Webform如此复杂, 主要是为了构造有层次结构的控件树, 实现事件驱动模型和维持控件postback后的状态, 而MonoRail是以controller/action/view为核心, 一个url对应的是controller的一个方法, 来自querystring, form post的数据SmartDispatcherController已经帮你处理好了, 你在action里要做的事情通常只是去处理它为你准备好的参数, 并且把view需要用到的对象放进PropertyBag里, 一切都是如此的简单