news 2026/7/4 20:44:25

Microsoft NLayerApp案例理论与实践 - 基础结构层(Cross-Cutting部分)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Microsoft NLayerApp案例理论与实践 - 基础结构层(Cross-Cutting部分)

NLayerApp中IoC容器的实现

在应用程序设计的过程中,我们会基于这样一个设计准则,就是类型之间的关联应该依赖于接口或者抽象,而非具体的实现。这样就使得我们能够在保证整个程序结构不变的情况下,很方便地替换组件的具体实现方式,这不仅使得Service Stub模式的应用成为可能,从而提高了系统的可测试性,而且解耦了组件之间的依赖关系,降低了应用程序的维护成本。IoC容器是这样一种对象,它在应用程序的执行环境中维护着接口与其实现之间的映射关系,以及各个实现对象之间的依赖关系,以便当客户程序向IoC容器提出请求时,能够返回与所请求的接口或抽象类型所对应的具体实现,客户程序不需要去关心返回的具体实现究竟是什么,以及如何去初始化这个具体实现。本文不会对IoC作过多的介绍,有兴趣的朋友可以阅读《Inversion of Control Containers and the Dependency Injection pattern》这篇文章。

NLayerApp中IoC容器的实现依赖于Microsoft Patterns&Practices Unity,其实大多数应用程序甚至是开发框架都会依赖于第三方的类库来实现IoC容器,因为IoC本身涉及的内容就比较多,很好地解决类型之间复杂的依赖关系也不是一件很容易的事情。Unity并非IoC的唯一选择,除了Unity之外,Spring.NET、Castle Windsor、Ninject、StructureMap等都可以成为IoC容器不错的选择。NLayerApp中与IoC容器实现有关的类及其之间的关系如下图所示:

在上图中,IContainer接口定义了IoC容器相关的方法,它是与具体的实现技术无关的接口(接口的层次结构树、其中定义的方法的参数以及返回值等都不会依赖于任何第三方的组件),因此,理论上我们可以通过继承IContainer接口然后用我们自己的技术方式来实现IoC容器。NLayerApp是使用Unity作为IoC容器的,因此,上图的IoCUnityContainer类实现了IContainer接口,然后在IoCFactory的单件实例中通过new关键字创建了IoCUnityContainer的实例:

1

2

3

4

5

6

7

8

9

10

#region Constructor

/// <summary>

/// Only for singleton pattern, remove before field init IL anotation

/// </summary>

staticIoCFactory() { }

IoCFactory()

{

_CurrentContainer =newIoCUnityContainer();

}

#endregion

当然,对于NLayerApp这一特定的应用程序案例而言,这样做是没什么问题的,但如果我们目前设计的是一个开发框架的话,直接使用new关键字来创建IoCUnityContainer的实例,就会使得IoCFactory强行依赖于IoCUnityContainer类型,于是也就违背了“关联应该依赖于接口或者抽象,而非具体实现”的设计准则。在最新版的Apworks框架的代码中,开发人员可以通过应用程序的配置信息来选择合适的IoC容器,比如你可以在应用程序启动的时候就决定是使用Unity还是Castle Windsor,这就使得框架本身具有更好的扩展性。刚才我们也讨论过,如果要使NLayerApp能够使用我们自定义的IoC容器,就要继承IContainer接口,那么现在我们还需要修改IoCFactory的私有构造函数,以使用我们自己的IoC容器来初始化_CurrentContainer私有成员。

Unity容器有一个非常实用的特点,就是“根容器”与“子容器”的概念,在“根容器”上通过调用CreateChildContainer方法即可创建与之关联的子容器。根容器和子容器都可以接受抽象类型的注册。每当客户程序向子容器请求类型(Resolve Type)时,Unity首先检查子容器中是否有所请求的类型,如果有,则直接返回该类型的具体实现,如果没有,则会将该请求转发给其父容器。利用Unity的这种特性,我们可以将针对不同部署环境的IoC容器进行统一管理,比如将各种部署环境中相同的类型映射注册在根容器中,然后为每个部署环境创建一个子容器,将与部署环境相关的特定类型映射注册在各自的子容器中。下图展示了NLayerApp中Unity IoC容器的基本情况:

通过阅读IoCUnityContainer的源代码我们可以了解到,在IoCUnityContainer的构造函数中,创建了rootContainer,并在rootContainer上使用CreateChildContainer创建了用于真实运行环境的realAppContainer以及用于单体测试的fakeAppContainer,之后就是使用下面的私有方法逐个初始化这些容器:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

/// <summary>

/// Configure root container.Register types and life time managers for unity builder process

/// </summary>

/// <param name="container">Container to configure</param>

voidConfigureRootContainer(IUnityContainer container)

{

// Omitted... Please refer to the source code for details.

}

/// <summary>

/// Configure real container. Register types and life time managers for unity builder process

/// </summary>

/// <param name="container">Container to configure</param>

voidConfigureRealContainer(IUnityContainer container)

{

container.RegisterType<IMainModuleUnitOfWork, MainModuleUnitOfWork>(newPerExecutionContextLifetimeManager(),

newInjectionConstructor());

}

/// <summary>

/// Configure fake container.Register types and life time managers for unity builder process

/// </summary>

/// <param name="container">Container to configure</param>

voidConfigureFakeContainer(IUnityContainer container)

{

//Note: Generic register type method cannot be used here,

//MainModuleFakeContext cannot have implicit conversion to IMainModuleContext

container.RegisterType(typeof(IMainModuleUnitOfWork),

typeof(FakeMainModuleUnitOfWork),newPerExecutionContextLifetimeManager());

}

在ConfigureRootContainer方法中,对所有环境(真实运行环境以及单体测试环境)需要用到的类型进行了注册,然后,就IMainModuleUnitOfWork而言,由于真实运行环境和单体测试环境所使用的Unit Of Work具体实现不同:真实运行环境使用的是MainModuleUnitOfWork实现,而测试环境则是使用的FakeMainModuleUnitOfWork,于是,也就在ConfigureRealContainer和ConfigureFakeContainer方法中分别作了注册。

最后,每当IContainer.Resolve方法被调用时,系统会通过读取配置文件来决定目前应该使用哪个容器来解析类型,因此,我们只需要在配置文件中正确设置容器的名称,即可在NLayerApp中使用指定的Unity IoC容器。下面这段配置信息来自于DistributedServices.Deployment项目,从中我们可以看到,NLayerApp的Distributed Services使用的是realAppContainer:

1

2

3

4

5

6

<appSettings>

<!--RealAppContext - Real Container-->

<!--FakeAppContext - Fake Container-->

<!--<add key="defaultIoCContainer" value="FakeAppContext" />-->

<addkey="defaultIoCContainer" value="RealAppContext" />

</appSettings>

NLayerApp中用于跟踪程序执行过程的Trace工具

NLayerApp中Trace工具的实现非常简单,在Infrastructure.CrossCutting项目中定义了ITraceManager,然后在Infrastructure.CrossCutting.NetFramework项目中定义了ITraceManager的具体实现。TraceManager使用了System.Diagnostics命名空间下与Trace相关的类型实现其功能,应用程序则通过IoCFactory来获得ITraceManager的具体实现。

在上面讨论的ConfigureRootContainer方法中,NLayerApp对ITraceManager类型进行了注册:

1

2

//Register crosscuting mappings

container.RegisterType<ITraceManager, TraceManager>(newTransientLifetimeManager());

因此,在整个应用程序中,就可以使用下面的方式来获取ITraceManager的具体实现,以便完成Trace功能:

1

2

ITraceManager traceManager = IoCFactory.Instance.CurrentContainer.Resolve<ITraceManager>();

traceManager.TraceError(/* error message*/);

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 20:43:27

终极免费漫画批量下载工具:E-Hentai下载器完整指南

终极免费漫画批量下载工具&#xff1a;E-Hentai下载器完整指南 E-Hentai下载器是一款强大的浏览器脚本工具&#xff0c;专门用于批量下载E-Hentai平台的漫画资源。这款漫画下载工具能够智能解析网页结构、实现多线程并行下载&#xff0c;并自动打包为ZIP文件&#xff0c;为用户…

作者头像 李华
网站建设 2026/7/4 20:42:37

当 AI 浏览器要拿走你的密码和 Cookie:Agent 浏览器的权限模型设计

前言 在上一篇《2026 浏览器大战转向 AI 代理》里&#xff0c;我们盘点了 Comet、Dia、Neon、Atlas、Aside、Jatter 六款新一代浏览器。它们的核心卖点高度一致&#xff1a;替你跨网站办事。但「替你办事」这四个字的工程含义&#xff0c;远比产品宣传页上写的要沉重——它意味…

作者头像 李华
网站建设 2026/7/4 20:41:57

合同全生命周期管理软件经验分享-实施流程

接上一篇帖子&#xff0c;这次我们普及一下中小项目快速实施的流程。因为在签订的合同&#xff0c;会包含诸多软件行业的专业词汇&#xff0c;甲方相关负责人在合同签订时需理解这些词汇&#xff0c;否则会影响对合同条款的判断&#xff0c;另外也会影响后续双方实施的计划配合…

作者头像 李华
网站建设 2026/7/4 20:41:47

30天从零精通ABAP RAP开发:完整指南与实战教程

30天从零精通ABAP RAP开发&#xff1a;完整指南与实战教程 【免费下载链接】abap-platform-rap-opensap Samples for the openSAP course "Building Apps with the ABAP RESTful Application Programming model (RAP)." 项目地址: https://gitcode.com/gh_mirrors/…

作者头像 李华
网站建设 2026/7/4 20:40:17

逆向工程实战:58同城App密码加密算法解析与Python复现

1. 项目概述与核心价值最近在和一些做数据采集、自动化测试的朋友交流时&#xff0c;经常听到一个话题&#xff1a;现在很多App的接口&#xff0c;尤其是涉及用户登录、交易等核心业务的接口&#xff0c;加密和风控做得越来越复杂&#xff0c;逆向分析的难度直线上升。这确实是…

作者头像 李华