Munq IocContainer V2 - 概述






4.33/5 (3投票s)
目录 下载代码 概述 Munq IocContainer 是什么 使用 Munq IocContainer 注册工厂方法 从 IocContainer 获取实例 初始化 IocContainer 生命周期管理 下载代码
目录
- 下载代码
- 概述
- Munq IocContainer 是什么
- 使用 Munq IocContainer
- 注册工厂方法
- 从 IocContainer 获取实例
- 初始化 IocContainer
- 生命周期管理
下载代码
概述
这篇帖子是系列文章中的第一篇,预告第二个版本 Munq IocContainer 的第一个 Beta 版本发布。在之前的帖子 ASP.NET 的 Munq IOC 容器入门介绍 和 将 Munq IOC 与 ASP.NET MVC 2 Preview 2 结合使用 中,我介绍了一个高性能且专为 ASP.NET 设计的 IOC 容器。最新版本修复了许多小问题并增加了功能,而没有牺牲任何性能。创建了单元测试以确保实现的质量和正确性。我认为这很重要,因为有几个人询问过在生产代码中使用 Munq IocContainer 的可能性。
此外,我还将发布 Munq FluentTest,这是一个用于 MSTest 或 NUnit 的流畅接口,允许测试中的验证语句以几乎英语的语法编写。IocContainer 的单元测试中可以看到示例。
本系列的第一个文章将是
- Munq IocContainer V2 – 概述(本文)
- Munq IocContainer V2 – 在 ASP.NET 应用程序中使用 Munq(可能分两部分)
- Munq IocContainer V2 – 使用生命周期管理消除不必要的实例创建
- Munq IocContainer V2 – 使用 Munq 实现自动插件或模块化应用程序
- Munq IocContainer V2 – 创建自定义生命周期管理器。
上述列表将在发生变更和出现奇思妙想时进行更新。
Munq IocContainer 是什么
如果您一直在使用或尝试使用 SOLID 原则进行编程,那么您就是在通过依赖倒置(SOLID 中的D)来实现类。简而言之,依赖倒置将解析依赖关系的责任转移到方法或构造函数的调用者,而不是方法或构造函数本身。这使得被调用的方法更容易测试,因为依赖关系可以通过单元测试代码中的模拟或存根进行替换。最简单的情况下,您可以使用“简陋的依赖注入”模式。这涉及到使用两个构造函数:一个接受传递的依赖关系,另一个是默认的(无参数构造函数),它调用另一个构造函数并使用默认的依赖实现。代码片段如下所示:
public class MyClass { // fields to hold references to the concrete implementations of // the class's dependencies. IDependencyOne _dependencyOne; IDependencyTwo _depencencyTwo; // constructor which allows the dependencies to be passed in. public MyClass(IDepenencyOne dependOne, IDependencyTwo dependTwo) { _dependencyOne = dependOne; _dependencyOne = dependTwo; } // default constructor which uses default implementations of // the class's dependencies/ public MyClass() : this(new ImplDependOne(), new ImplDependTwo()) { } public void AMethod(int a) { var b = _dependencyOne.MethodA(a); _dependencyTwo.MethodB(b); } ... }
生产代码调用默认构造函数,而单元测试使用带有参数的构造函数。不幸的是,这仍然使 *MyClass* 耦合到具体的实现 *ImplDependOne* 和 *ImplDependTwo*。
可以通过删除默认构造函数来移除此依赖关系。但是,这意味着每次创建 *MyClass* 的实例时,代码还必须创建实现 *IDependencyOne* 和 *IDependencyTwo* 的类的实例。这就是 IOC 容器的作用。IOC 容器可以被查询以获取接口或抽象类的实现,并返回一个包含所有已解析依赖关系的实例。
使用 Munq IocContainer,这需要两个步骤。首先是向容器注册一个工厂方法,其次是使用容器来解析依赖关系。Munq IocContainer 注册接收 IocContainer 实例并返回实现所请求接口的实例的方法。通过使用工厂方法而不是类,开发人员可以完全控制实例的创建过程。此外,由于无需使用 *反射* 或其他 CPU 密集型技术来选择构造函数并解析其依赖关系,因此容器的解析速度尽可能快。因此,前面的示例将如下所示:
public class MyClass : IMyClass { // fields to hold references to the concrete implementations of // the class's dependencies. IDependencyOne _dependencyOne; IDependencyTwo _depencencyTwo; // constructor which allows the dependencies to be passed in. public MyClass(IDepenencyOne dependOne, IDependencyTwo dependTwo) { _dependencyOne = dependOne; _dependencyOne = dependTwo; } public void AMethod(int a) { var b = _dependencyOne.MethodA(a); _dependencyTwo.MethodB(b); } ... } ... ///////////////////////////////////////////////////////////////////////////// // Registration, probably in Global.asax for an ASP.NET application public static Container { get; private set;} private void InitIocContainer() { // create the container Container = new IocContainer(); // Register the interface implementations. Container.Register<IMyClass>(c => new MyClass(c.Resolve<IDependencyOne>(), c.Resolve<IDependencyTwo>()) ); Container.Register<IDependencyOne>(c => new ImplDependOne() ); Container.Register<IDependencyTwo>(c => new ImplDependTwo() ); } ... ///////////////////////////////////////////////////////////////////////////// // getting the class instance from the container IMyClass instance = MyApp.Container.Resolve<IMyClass>(); instance.MethodA(42);
如果您熟悉 Unity、NInject、AutoFac、Windsor 或 StructureMap 等更知名的 IOC 容器,您可能会想:“这和所有其他容器都一样”。您基本上是正确的。区别在于 Resolve 功能的速度和面向 Web 的生命周期管理功能。有关 Munq 与其他 IOC 容器性能的详细信息,请参阅我之前的文章 ASP.NET 的 Munq IOC 容器入门介绍。您还可以从 Omar AL Zabir(DropThings 的创建者)那里获得另一个观点,请参阅 Munq 适合 Web,Unity 适合企业。但简单回顾一下,IOC 容器的相对性能如下所示,越小越好。
使用 Munq IocContainer
Munq 的第二个版本已重构为两个 DLL。第一个是Munq.Interfaces,仅包含使用 IIocContainer 实例、IRegistration 对象(从 IIocContainer.Register 方法之一返回)或创建自己的生命周期管理器所需的接口。通过面向接口编程,只有主应用程序需要对 Munq IOC Container 进行硬编码依赖。其他 DLL 可以将容器实例作为 IIocContainer 传递。这允许在需要时将 IOC Container 替换为另一个实现。
第二个 DLL,Munq.IocContainer,包含 Munq IOC Container 的实现、标准的生命周期管理器、配置加载器以及 ASP.NET MVC 的 Controller Factory。
注册工厂方法
Munq 允许您使用泛型或非泛型方法注册一个命名或未命名的工厂方法,总共有 4 种不同的 Register 方法签名。同样,有 4 种方法用于注册一个预先构造的实例,以便在Resolve请求时始终返回该实例。
//Register IRegistration Register(string name, Type type, Func<IIocContainer, object> func); IRegistration Register(Type type, Func<IIocContainer, object> func); IRegistration Register<TType>(Func<IIocContainer, TType> func) where TType : class; IRegistration Register<TType>(string name, Func<IIocContainer, TType> func) where TType : class; //Register Instance IRegistration RegisterInstance(string name, Type type, object instance); IRegistration RegisterInstance(Type type, object instance); IRegistration RegisterInstance<TType>(string name, TType instance) where TType : class; IRegistration RegisterInstance<TType>(TType instance) where TType : class;
所有 RegisterXXX 方法都返回一个实现 IRegistration 接口的对象。此接口允许您获取有关注册的信息、指定 LifetimeManger 或使任何缓存的实例失效。
public interface IRegistration { string Name { get; } string Key { get; } Type ResolvesTo { get; } IRegistration WithLifetimeManager(ILifetimeManager manager); void InvalidateInstanceCache(); }
从 IocContainer 获取实例
用户通过调用 Resolve 方法之一来请求容器创建或提供一个接口实现的缓存实例。例如:
// getting the class instance from the container IMyClass instance = MyApp.Container.Resolve<IMyClass>(); instance.MethodA(42);
容器返回所需类型的实例,所有依赖项都已解析并完全初始化。
//Resolve object Resolve(string name, Type type); object Resolve(Type type); TType Resolve<TType>() where TType : class; TType Resolve<TType>(string name) where TType : class;
//Lazy Resolve Func<object> LazyResolve(string name, Type type); Func<object> LazyResolve(Type type); Func<TType> LazyResolve<TType>() where TType : class; Func<TType> LazyResolve<TType>(string name) where TType : class;
// Example of LazyResolve Func<MyClass> lazyLoader = Container.LazyResolve<MyClass>(); // do stuff ... if (INeedMyClass) { using(MyClass myClass = lazyLoader()) { // do stuff with myClass ... } }
初始化 IOC Container
IOC 容器的初始化可以通过多种方式进行,但通常发生在 ASP.NET 应用程序的 Global.asax 文件的 Application_Start 中。Munq 开箱即用地支持
- 通过代码初始化
- 自动发现和注册
通常,应用程序将同时使用这两者。例如,下面的代码有一个 InitializeIOC 方法,它调用 ConfigurationLoader.FindAndRegisterDependencies 方法以及 Register<..> 方法。
FindAndRegisterDependencies 方法接收 IIocContainer 作为参数,并执行以下操作:
- 搜索 bin 目录中的所有实现 IMunqConfig 接口的类。
- 为每个类创建一个实例,并调用 RegisterIn 方法,将容器传递给它。
- 这些方法允许模块向容器注册其类和依赖项。
显式注册允许注册工厂方法及其依赖项。查看下面的 Register<IController>("Account", …) 语句。该行翻译成英语是:“当请求 IController 接口的实例,名为“Account”时,通过调用构造函数来创建实例。将 IFormsAuthentication 和 IMembershipService 的实例传递给构造函数,它们也都由容器解析,就像它们的任何依赖项一样。”
public class MvcApplication : System.Web.HttpApplication { public static Container IOC { get; private set; } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { InitializeIOC(); RegisterRoutes(RouteTable.Routes); } private void InitializeIOC() { // Create the IOC container IOC = new Container(); // Create the Default Factory var controllerFactory = new MunqControllerFactory(IOC); // set the controller factory ControllerBuilder.Current.SetControllerFactory(controllerFactory); ConfigurationLoader.FindAndRegisterDependencies(IOC); // Register the Controllers IOC.Register<IController>("Home", ioc => new HomeController()); IOC.Register<IController>("Account", ioc => new AccountController(ioc.Resolve<IFormsAuthentication>(), ioc.Resolve<IMembershipService>()) ); } }
生命周期管理
生命周期管理功能自版本 1 以来没有改变,尽管实现已有所不同。
生命周期管理器允许您修改容器在解析实例方面的行为以及实例的生命周期。Munq 拥有一套专为 Web 应用程序设计的生命周期管理器。这些如下所述。
警告:如果您使用了 RegisterInstance
方法,那么无论使用哪种生命周期管理器,都会返回相同的实例。
AlwaysNewLifetime
此生命周期管理器的行为是,当调用 Resolve
方法时,通过执行工厂方法始终返回一个新实例。这是默认行为。
ContainerLifetime
此生命周期管理器的行为是,当调用 Resolve
方法时,通过执行工厂方法始终返回同一个实例。该实例在容器本身中缓存。
SessionLifetime
此生命周期管理器的行为是,当调用 Resolve
方法时,始终尝试从 Session
检索实例。如果实例不存在于 Session
中,则通过执行工厂方法创建一个新实例,并将其存储在 Session
中。
RequestLifetime
此生命周期管理器的行为是,当调用 Resolve
方法时,始终尝试从 Request.Items
检索实例。如果实例不存在于 Request.Items
中,则通过执行工厂方法创建一个新实例,并将其存储在 Request.Items
中。
CachedLifetime
此生命周期管理器的行为是,当调用 Resolve
方法时,始终尝试从 Cache
检索实例。如果实例不存在于 Cache
中,则通过执行工厂方法创建一个新实例,并将其存储在 Cache
中。CachedLifetimeManager 可以应用 CacheDependencies 和滑动或绝对超时。
结论
本文只是对 Munq IocContainer 的功能和性能进行了简要概述。我将在本系列的后续文章中探讨使用 Munq.IocContainer 的不同方面,敬请关注。