寂寞如此美丽:脱离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
}

  小结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值