• 寂寞如此美丽:脱离Application_Start,让初始化代码更优美


      这里的“寂寞”指的是将ASP.NET程序中的初始化代码从Global.asax.cs的Application_Start()方法中,移至单独的程序集中,并且这个程序集与Web项目的程序集没有任何来往。比如,初始化代码所在的程序集叫CNBlogs.BootStrapper,Web项目的程序集叫CNBlogs.Web,在Visual Studio中,这两个项目之间没有任何引用关系。

      因为低耦合而变得寂寞,代码却因此变得更美。在生活中,寂寞可以让人保持内心的宁静,可以享受更多思考之美。

      这篇文章通过两种方法让初始化代码变得更优美:

      1)PreApplicationStartMethod(ASP.NET 4.0的新特性,详见这里)。

      2)Bootstrapper(codeplex上的开源项目,详见 http://bootstrapper.codeplex.com/)。

      使用Application_Start()的场景

      先看一下不使用Bootstrapper,直接在Application_Start()进行初始化的示例代码:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
    filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
    }

    protected void Application_Start()
    {
    //MVC的注册
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    //IOC容器的注册
    var container = IoCFactory.Instance.CurrentContainter;
    container.RegisterType<IBlogSiteService, FakeBlogSiteService>();
    container.RegisterType<IBlogPostService, FakeBlogPostService>();
    }

      这是一种常用场景,在Application_Start()中完成一些初始化注册与配置,但这些代码堆在一起,看着总是不顺眼。

      当使用了测试驱动开发(TDD)之后,不仅看着不顺眼,而且用着也不顺手,因为在测试项目中也要进行初始化,但测试项目无法调用Application_Start()方法。

      我们当时将这部分初始化代码移至独立的程序集(CNBlogs.BootStrapper),就是因为测试所需。独立出来后,Application_Start()与测试项目都通过调用CNBlogs.BootStrapper.Initializer.Initialize()方法完成初始化。

      这样虽然独立了,但并不寂寞,也不美丽。因为:

      1. Web项目要依赖CNBlogs.BootStrapper;

      2. 这些初始化代码依然堆在一些,只是换了个地方。

      解决方法

      针对第一个问题 » 用ASP.NET 4.0的新特性PreApplicationStartMethod来解决。在CNBlogs.Bootstrapper项目的AssemblyInfo.cs添加如下的代码:

    [assembly: PreApplicationStartMethod(typeof(CNBlogs.Bootstrapper.Initializer), "Initialize")]

      注:CNBlogs.Bootstrapper.Initializer是静态类,Initialize中Initializer中的静态方法。

      ASP.NET Runtime会自动在程序集中发现这个定义,并在调用Application_Start()之前执行这里指定的Initialize方法。

      需要注意的是,AreaRegistration.RegisterAllAreas();只能放在Application_Start()中执行,否则会报错:

      This method cannot be called during the application's pre-start initialization stage.

       针对第二个问题 » 通过 Bootstrapper 将不同的初始化代码组织成不同的任务(实现IStartupTask接口),然后通过Bootstrap.Bootstrapper的Fluent API调用这些任务,并且可以指定任务的执行顺序。比如,我们有两个任务IocRegisterTask与RegisterRoutesTask,IocRegisterTask要先执行,运行这两个任务的代码如下:

    public static class Initializer
    {
    public static void Initialize()
    {
    Bootstrap.Bootstrapper.With.StartupTasks()
    .UsingThisExecutionOrder(s => s.First<RegisterRoutesTask>().Then<IocRegisterTask>())
    .Start();
    }
    }

      IoCRegisterTask的实现代码如下:

    public class IocRegisterTask : IStartupTask
    {
    #region IStartupTask Members

    public void Run()
    {
    var container = IoCFactory.Instance.CurrentContainter;
    container.RegisterType<IBlogSiteService, FakeBlogSiteService>();
    container.RegisterType<IBlogPostService, FakeBlogPostService>();
    }

    public void Reset()
    {
    }

    #endregion
    }

      RegisterRoutesTask的实现代码如下:

    public class RegisterRoutesTask : IStartupTask
    {
    #region IStartupTask Members

    public void Run()
    {
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    }

    private void RegisterRoutes(RouteCollection routes)
    {
    routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
    }

    public void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
    filters.Add(new HandleErrorAttribute());
    }

    public void Reset()
    {
    }

    #endregion
    }

      小结

      代码之美与文学、绘画、音乐一样,没有最美,只有更美。其中的过程是无止境的,其中的乐趣也是无止境的,当然前提是你真正喜欢它。有人说写程序是吃青春饭,这绝对是个错误的想法!因为文学家、画家、音乐家没有吃青春饭的,程序员也一样!写到这里,突然想到,当年老的时候,把年轻时候写的代码拿出来重构一下,一定会很有意思!

  • 相关阅读:
    iBatis.Net(2):基本概念与配置
    iBatis.Net(4):DataMapper API
    iBaits.Net(1):简介与安装
    在YII项目中使用ckeditor和ckfinder快速部署文本编辑器并实现图片上传
    iBatis.Net(6):Data Map(深入)
    基于.net mvc的校友录(开篇)
    Ubuntu下建立tftp服务+我安装过程出现的问题
    2013年了,今年我将毕业
    路由器系统的内存储布局
    基于.net mvc的校友录(一、前台需求设计)
  • 原文地址:https://www.cnblogs.com/dudu/p/application_start_bootstrapper.html
Copyright © 2020-2023  润新知