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的更多相关文章

  1. 自己动手做Web框架—MVC+Front Controller

    在我前面一篇博文<逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎>发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了. 同时,这也是eLiteWeb开源软件的一 ...

  2. Spring mvc框架 controller间跳转 ,重定向 ,传参

     一.需求背景     1. 需求:spring MVC框架controller间跳转,需重定向.有几种情况:不带参数跳转,带参数拼接url形式跳转,带参数不拼接参数跳转,页面也能显示.   @Req ...

  3. Asp.net MVC 中Controller返回值类型ActionResult

    [Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...

  4. [Design Pattern] Front Controller Pattern 简单案例

    Front Controller Pattern, 即前端控制器模式,用于集中化用户请求,使得所有请求都经过同一个前端控制器处理,处理内容有身份验证.权限验证.记录和追踪请求等,处理后再交由分发器把请 ...

  5. MVC:Controller向View传值方式总结

    Controller向View传值方式总结 总结发现ASP.NET MVC中Controller向View传值的方式共有6种,分别是: ViewBag ViewData TempData 向普通Vie ...

  6. 返璞归真 asp.net mvc (3) - Controller/Action

    原文:返璞归真 asp.net mvc (3) - Controller/Action [索引页] [源码下载] 返璞归真 asp.net mvc (3) - Controller/Action 作者 ...

  7. spring mvc在Controller中获取ApplicationContext

    spring mvc在Controller中获取ApplicationContext web.xml中进行正常的beans.xml和spring-mvc.xml的配置: 需要在beans.xml中进行 ...

  8. MVC中Controller控制器相关技术

    第6章Controller相关技术 Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务器端的交互,并 且负责协调Model与View之间的数椐传递,是ASP.NET MV ...

  9. ASP.NET Core MVC中Controller的Action,默认既支持HttpGet,又支持HttpPost

    我们知道ASP.NET Core MVC中Controller的Action上可以声明HttpGet和HttpPost特性标签,来限制可以访问Action的Http请求类型(GET.POST等). 那 ...

随机推荐

  1. java中string和int互相转化

    1 怎样将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 i = Integer.parseInt([ ...

  2. java设计模式之九外观模式(Facade)

    外观模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口 ...

  3. 一步一步写算法(之挑选最大的n个数)

    原文:一步一步写算法(之挑选最大的n个数) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 从一堆数据中挑选n个最大的数,这个问题是网上流传的 ...

  4. JS模块与命名空间的介绍

    起因将代码组织到类中的一个重要原因是让代码更加“模块化”,可以在很多不同的场景中实现代码的重用.但类不是唯一的模块化代码的方式. 一般来讲,模块是一个独立的JS文件.模块文件可以包含一个类定义.一组相 ...

  5. 大数据时代:基于微软案例数据库数据挖掘知识点总结(Microsoft 聚类分析算法)

    原文:(原创)大数据时代:基于微软案例数据库数据挖掘知识点总结(Microsoft 聚类分析算法) 本篇文章主要是继续上一篇Microsoft决策树分析算法后,采用另外一种分析算法对目标顾客群体的挖掘 ...

  6. AJAX入门——工作原理

    同步和异步交互,了解互动 对于一个样本:一般B/S模式(同步)       AJAX技术(异步)        *  同步:       提交请求->等待server处理->处理完成返回 ...

  7. Web前端框架与类库

    Web前端框架与类库的思考 说起前端框架,我也是醉了.现在去面试或者和同行聊天,动不动就这个框架碉堡了,那个框架好犀利. 当然不是贬低框架,只是有一种杀鸡焉用牛刀的感觉.网站技术是为业务而存在的,除此 ...

  8. vue实现ajax滚动下拉加载,同时具有loading效果

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Lucene.net入门学习

    Lucene.net入门学习(结合盘古分词)   Lucene简介 Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全 ...

  10. sqlclr创建表值函数案例

    ----------------------------------------------:定义表值类型:(1.一定返回的是IEnumerable2.一定带参数3.一定有FillRowMethodN ...