MVC+Front Controller
MVC+Front Controller
在我前面一篇博文《逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎》发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了。
同时,这也是eLiteWeb开源软件的一部分。
MVC + Front Controller
我 们常常提到的MVC中作为Controller的C。其实有两项任务,一个是处理Http请求,另一个是对请求中的用户数据进行的处理。前者,有:安全认 证,Url映射等。Front Controller 模式就是把这个C进一步分离。两个责任两个类(单一责任原则)。因此,这里给我的MVC模式,赋予新的内涵C => Command,以诠释两个模式的融合。
非我族类,拒之门外 --- 转换器BasicHttphandler
这是一个Adapter目的就是为了把ASP.Net环境转化为我自定义的Web抽象。
首先就是BasicHttphandler本身实现了IHttpHandler,并在Web.config中设置为默认的系统HttpHandler,把控制权拿了过来,我的世界我做主。
其次,把HttpContext转换为自定义的WebRequest,然后传递给Front Controller作进一步的处理处理。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class BasicHttpHandler:IHttpHandler { public class BasicHttpHandler:IHttpHandler { private FrontController front_controller; private WebRequestAdapter web_request_adapter; public BasicHttpHandler(WebRequestAdapter webRequestAdapter, FrontController frontController) { web_request_adapter = webRequestAdapter; front_controller = frontController; } public BasicHttpHandler() : this(Container.get_a<WebRequestAdapter>(),Container.get_a<FrontController>()) {} public void ProcessRequest(HttpContext context) { front_controller.process(web_request_adapter.create_from(context)); } public bool IsReusable { get {return true; } } } |
总阀门 --- Front Controller
它的实现也很简单,就是通过命令解析器CommandResolver,找到可执行的命令,传入WebRequest进行处理。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[RegisterInContainer(LifeCycle.single_call)] public class FrontControllerImpl : FrontControllers.FrontController { private CommandResolver command_resolver; public FrontControllerImpl(CommandResolver commandResolver) { command_resolver = commandResolver; } public void process(WebRequest request) { command_resolver.get_command_to_process(request).process(request); } } |
从流程上,到这里整个处理已经完成;剩下的可以看作是你自己功能的扩展。
以下可以看作是我的一个具体简单实现。
Command系列接口
前 面提到的命令解析器我就是简单用到一个Command集合(IEnumerable<Command>),而寻找执行命令这一逻辑,是通过 Command自身的方法can_process(WebRequest)的调用,从而巧妙的把责任分布到每个具体Command自身去了。这就是集中规则,分散责任。其实,依赖注入的实现中,声明式注入(RegisterInContainerAttribute)也是类似的场景。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[RegisterInContainer(LifeCycle.single_call)] public class CommandResolverImpl : CommandResolver { private IEnumerable<Command> available_commands; public CommandResolverImpl(IEnumerable<Command> availableCommands) { available_commands = availableCommands; } public Command get_command_to_process(WebRequest request) { return available_commands.First(x => x.can_process(request)); } } |
仔细看看Command,这一接口又分解为两个粒度更小的接口:DiscreteCommand和过滤器Command。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public interface Command : DiscreteCommand, CommandFilter { } public interface DiscreteCommand { void process(WebRequest request); } public interface CommandFilter { bool can_process(WebRequest request); } |
从它们各自带的方法可以清晰的看到它们的角色分工,前者是具体处理用户数据,之后的所有具体命令处理类,如Index, Home都要实现这个接口,一个方法,从而其间简洁与单纯性已是做到了极致;后者就是命令过滤,承担选择可执行命令的责任,Url的路由映射就实现这个接 口,我这里只简单实现了用正则映射(过滤)器 RegularExpressFilter。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class RegularExpressFilter:CommandFilter { private readonly Regex regex; public RegularExpressFilter(string match) { regex = new Regex(match); } public bool can_process(WebRequest request) { return regex.IsMatch(request.Input.RequestPath); } } |
View
视图的这一部分,就到跳到每一个具体的命令类中了,如 Index类中,通过调用WebRequest.Output.Display(View, Model),后台把调用传递到ViewEngin的一个实现类。需要知道更详细,可以到参考前文《代码整洁之道------Razor Compiler的重构》
便用示例
当要为你的Web程序创建一个页面时,只有三步:
第一步:创建一个类实现DiscreteCommand接口,并注册到Container中。在process(WebRequest)完成你需要的功能,我这只是显示一些文本,作为演示。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[RegisterInContainer(LifeCycle.singleton)] public class Index:DiscreteCommand { public void process(WebRequest request) { request.Output.Display(new View("Index"), @" <h3>卓越之行</h3><p>宏卓科技公司专注于最新软件开发技术、开发流程和业务服务。让所有这些技术为了一个目标---您的业务服务. </p><ul> <li> 使用行为/测试驱动方式追溯需求,驱动开发,不丢需求 </li> <li> 利用敏捷流程提高用户体验,降低风险 </li> <li> 使用良好的架构提高系统的扩展性和维护性,同时降低开发的可变成本 </li> <li> 利用对业务流程的深入了解,开发适用软件,提供业务服务,使服务与软件无缝结合、同步发展。</li><ul><p>终极目标:动成长软件,让我们的系统与你公司的业务一起成长。</p>" ); } |
第二步:在映射注册类RoutesRegistration中,填加一条映射记录.。因为我不已经用命令工厂类封装了正则过滤器,所以代码看起来简单而易读一些。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class RoutesRegistration:StartupCommand { private Registration registration; public RoutesRegistration(Registration registration) { this.registration = registration; } public void run() { var routes = Container.Current.get_a<RoutingTable>(); var factory = new CommandFactory(); routes.add(factory.match<Home>("Home.do")); routes.add(factory.match<Index>("Index.do")); } } |
第三步:创建Razor页面
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@inherits Skight.eLiteWeb.Presentation.Web.ViewEngins.TemplateBase<string>@{ Layout = "_Layout.cshtml";}<head runat="server"> <title>Index 页面</title></head> <body> <h2>宏卓科技 与你公司的业务一起成长!</h2> <img src="/Theme/Index_pepole.jpg" style="float: left; margin-right: 50px;" /> @Model</body></html> |
总结:是的,这里的具体功能很简单,但是,相信你也看到了其强大的扩展性,如Url映射的扩展和Command扩展。与Asp.Net不同,我这里一个Web请求是用一个类来处,而不是一个方法,这样,继承、重用和扩展都很方便。
最后一个优势:所有的处理类都是自定义的轻型类,继承层次较少,对外部的依赖为0,这个于性能是大有裨益的。
这也是把轻型作为框架名称的含义:对外依赖的轻型,性能上的轻型。
(本文版权属于© 2012 - 2013 予沁安 | 转载请注明作者和出处WangHaoBlog.com)
最后,一全景类图和序列图做结。



MVC+Front Controller的更多相关文章
- 自己动手做Web框架—MVC+Front Controller
在我前面一篇博文<逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎>发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了. 同时,这也是eLiteWeb开源软件的一 ...
- Spring mvc框架 controller间跳转 ,重定向 ,传参
一.需求背景 1. 需求:spring MVC框架controller间跳转,需重定向.有几种情况:不带参数跳转,带参数拼接url形式跳转,带参数不拼接参数跳转,页面也能显示. @Req ...
- Asp.net MVC 中Controller返回值类型ActionResult
[Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...
- [Design Pattern] Front Controller Pattern 简单案例
Front Controller Pattern, 即前端控制器模式,用于集中化用户请求,使得所有请求都经过同一个前端控制器处理,处理内容有身份验证.权限验证.记录和追踪请求等,处理后再交由分发器把请 ...
- MVC:Controller向View传值方式总结
Controller向View传值方式总结 总结发现ASP.NET MVC中Controller向View传值的方式共有6种,分别是: ViewBag ViewData TempData 向普通Vie ...
- 返璞归真 asp.net mvc (3) - Controller/Action
原文:返璞归真 asp.net mvc (3) - Controller/Action [索引页] [源码下载] 返璞归真 asp.net mvc (3) - Controller/Action 作者 ...
- spring mvc在Controller中获取ApplicationContext
spring mvc在Controller中获取ApplicationContext web.xml中进行正常的beans.xml和spring-mvc.xml的配置: 需要在beans.xml中进行 ...
- MVC中Controller控制器相关技术
第6章Controller相关技术 Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务器端的交互,并 且负责协调Model与View之间的数椐传递,是ASP.NET MV ...
- ASP.NET Core MVC中Controller的Action,默认既支持HttpGet,又支持HttpPost
我们知道ASP.NET Core MVC中Controller的Action上可以声明HttpGet和HttpPost特性标签,来限制可以访问Action的Http请求类型(GET.POST等). 那 ...
随机推荐
- 【百度地图API】如何进行地址解析与反地址解析?——模糊地址能搜索到精确地理信息!
原文:[百度地图API]如何进行地址解析与反地址解析?--模糊地址能搜索到精确地理信息! 摘要: 什么是地址解析? 什么是反地址解析? 如何运用地址解析,和反地址解析? 可以同时运用地址解析,和反地址 ...
- uploadfiy 动态传递Form 参数
参见 百度 http://jingyan.baidu.com/article/a3a3f8118b1c4d8da3eb8a60.html @{ ViewBag.Title = "Ind ...
- JS代码的几个注意点规范
也谈谈规范JS代码的几个注意点 也谈谈规范JS代码的几个注意点 写JS代码差不多也有两年了吧,从刚开始的“初生牛犊不怕虎”乱写一通到后来也慢慢知道去规范一下自己写的代码.这种感觉就像是代码是你的作品, ...
- 关于Java中List对象的分页思想,按10个或者n个数对list进行分组
try { List<String> timelist = DateUtils.getDateListBySETime("2015-08-01", "2015 ...
- Java清理临时目录文件Demo(一)
/** * 删除单个文件 * * @param sPath * 被删除文件的文件名 * @return 单个文件删除成功返回true,否则返回false */ public static boolea ...
- 完整的thinphp+phpexcel实现excel报表的输出(有图有效果)
准备工作:1.下载phpexcel1.7.6类包:2.解压至TP框架的ThinkPHP\Vendor目录下,改类包文件夹名为PHPExcel176,目录结构如下图: 编写代码(以一个订单汇 ...
- HDU 5185 Equation (DP)
题目:LINK 题意:求满足题目要求的x序列的种类数. 能够发现符合条件的序列去重后是一个0, 1, ..., k的连续序列(k满足k*(k+1)/2 <= n) ,则这个去重后的序列长度最长为 ...
- solr与.net主从复制
solr主从复制 solr与.net系列课程(七)solr主从复制 既然solr是解决大量数据全文索引的方案,由于高并发的问题,我们就要考虑solr的负载均衡了,solr提供非常简单的主从复制的 ...
- leetcode N-QueensII
题目和上一题一样,就是要求输出有多少种结果.最直接的就是,只要在上一题的代码return ans.size();就可以了.果然也是AC了. 然后我翻看了几种别人写的,暂时还没有找到复杂度可以比上一题降 ...
- MSSQL2008数据库备份还原和数据恢复
原文:MSSQL2008数据库备份还原和数据恢复 序言 一直想写一篇关于数据库备份与恢复的文章,但基于能力的有限对数据库认知的有限怕不足以准确的表达,最后思考很久还是决定把自己的一些理解写出来供大 ...