基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 对象控制反转

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 控制反转,即IOC(Inversion of Control),也叫反转模式,也称依赖注入DI(Dependency Injection)模式,关于此概念的解释我在此文不做过讲说明。      对于设计模式类的东西,我也没有认真系统的去研究过那X类N种设计模式,无论何种设计模式,都用于解决一个问题,那就是解决对象之间的耦合关系,即解耦。

     控制反转,即IOC(Inversion of Control),也叫反转模式,也称依赖注入DI(Dependency Injection)模式,关于此概念的解释我在此文不做过讲说明。

     对于设计模式类的东西,我也没有认真系统的去研究过那X类N种设计模式,无论何种设计模式,都用于解决一个问题,那就是解决对象之间的耦合关系,即解耦。

     AgileEAS.NET在最初版本最不包含IOC容器,更多应用抽象工厂之类的设计模式,在这AgileEAS.NET大概第二个版本,加入了一个轻量级(微量级)的IOC容器,也许实现的并不优雅,在多年的应用中慢慢完善。

      以下我列举一个 AgileEAS.NET平台IOC容器的一个应用场景,在某个产品开发中,有的产品使用ORACLE数据库、有的客户使用SQLServer数据库,这就要求我们必须做到产品同时支持两种数据库,我们在开发中对数据DAL采用其他接口驱动的设计,即定义三个项目:DAL接口、DAL的SQLServer实现、DAL的ORACLE实现,假定三个项目名称为Exam.DAL.Interface、Exam.DAL.SQLServer、Exam.DAL.Oracle;我们在Exam.DAL.Interface中定义N个业务对象接口和一个管理这些业务对象接口的IDALManager接口:

    public interface IDALManager
    {
        IIteminfo CreateIteminfo();

        IIteminfoList CreateIteminfoList();

        IProduct CreateProduct();

        IProductList CreateProductList();
    }
 
    我们在Exam.DAL.SQLServer、Exam.DAL.Oracle中分别实现业务接口和IDALManager接口:
    public class DALManager : IDALManager
    {
         public IIteminfo CreateIteminfo()
        {
            return new Iteminfo();
        }

        public IIteminfoList CreateIteminfoList()
        {
            return new IteminfoList();
        }

        public IProduct CreateProduct()
        {
            return new Product();
        }

        public IProductList CreateProductList()
        {
            return new ProductList();
        }
    }

      我们力争在设计中使用接口驱动并且使用具体被调用者在运行期确认,当然在这样的应用场景中除了IOC容器之外可以用其他模式进行实现,我在此不做说明。

    我们在Exam.DAL.Interface增加一个公共类DALHelper并做如下定义:

    public class DALHelper
    {
        public DALHelper()
        {
        }

        public static IDALManager DALManager
        {
            get
            {
                return ContextHelper.GetContext().Container.GetComponentInstance("EAS.Exam.DAL") as IDALManager;
            }
        }
    }

    修改系统配件文件中的IOC定义:

<object name="EAS.Exam.DAL" assembly="EAS.Exam.DAL.SQLServer" type="EAS.Exam.DAL.SQLServer.DALManager" LifestyleType="Singleton" />

     这样我们就完成了对IDALManager与具体实例化对象完成了结偶,当然上例只是一个很简单的例子,AgileEAS.NET中的IOC实现了构造注入和属性注入,以下配置示例:

    <object name="MasterDbConnection" assembly="EAS.Data" type="EAS.Data.Access.OleDbConnection" LifestyleType="Singleton">
      <property name="ConnectionString" type="string" value="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=sa;Initial Catalog=eas;Data Source=vm2003" />
    </object>
    <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Singleton">
      <property name="DbConnection" type="object" value="MasterDbConnection" />
    </object>
    <object name="CacheAccessor" assembly="EAS.Data" type="EAS.Data.ORM.CacheAccessor" LifestyleType="Singleton">
    </object>
    <object name="MasterDataAccessor" assembly="EAS.Data" type="EAS.Data.Access.OleDbAccessor" LifestyleType="Singleton">
      <property name="Connection" type="object" value="MasterDbConnection" />
    </object>
    <object name="MasterRMIAccessor" assembly="EAS.Distributed.WebServiceClient" type="EAS.Distributed.WebServiceClient.RMIAccessor" LifestyleType="Singleton">
      <constructor-arg index="0" type="string" value="http://demo.smarteas.net/activexform/Distributed/RMIService.asmx" />
    </object>

        对于IOC容器中的对象生存方式定义如下:

 

	/// <summary>
	/// 枚举LifestyleType 组件的生存方式,即组件以何种生存周期在容器中生存。
	/// </summary>
	public enum LifestyleType
	{
		/// <summary>
		/// Undefined,没有定义生存周期,即以默认生存周期(Transient)。
		/// </summary>
		Undefined = 0x00000000,

		/// <summary>
		/// Singleton,组件一旦自在,则在所有的客商端中共享。
		/// </summary>
		Singleton = 0x00000001,

		/// <summary>
		/// Thread,每一个客户端线程拥有单独的一个实例。
		/// </summary>
		Thread = 0x00000002,

		/// <summary>
		/// Transient,组件在使用时创建、使用后销毁。
		/// </summary>
		Transient = 0x00000004,

		/// <summary>
		/// Pooled,组件池,初始时分配一定数量的组件,客户请求时,分配一个空闲组件,用户使用完后交由池中。
		/// </summary>
		Pooled = 0x00000008
	}

在使用中IOC提供了基于配置文件和程序配置两种方式进行对象配置,IOC容器使用组件容器IContainer和IOC上下文环境IContext提供服务,IContainer定义如下:

IContainer	/// <summary>
	/// 的组件容器,组件容器管理组件的生存,也是对外提供的一个接口。
	/// </summary>
    public interface IContainer : IDisposable
	{	
		/// <summary>
		/// 根据组件组件key向容器注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		void AddComponent(string componentKey);

		/// <summary>
		/// 根据组件组件key及组件实现类型向容器注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="componentImplementation"></param>		
		void AddComponent(string componentKey, Type componentImplementation);

		/// <summary>
		/// 根据组件key、接口类型及实现类型中注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="serviceType">组件接口类型。</param>
		/// <param name="componentImplementation">组件实现类型。</param>
		void AddComponent(string componentKey, Type serviceType, Type componentImplementation);

		/// <summary>
		/// 根据组件实现类型及组件接口类型向容器注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="componentImplementation">组件实现类型。</param>
		/// <param name="serviceType">组件接口类型。</param>
		/// <param name="lifestyleType"> 组件生命周期方式。</param>
		/// <param name="lifestyleParameters"> 组件生命周期相关参数,参数为一个字符串,其中由“:”分隔。</param>
		void AddComponent(string componentKey,Type serviceType,Type componentImplementation,Lifecycle.LifestyleType lifestyleType,string lifestyleParameters);
		
		/// <summary>
		/// 根据组件实现类型向容器注册组件实现。
		/// </summary>		
		/// <param name="componentImplementation">组件实现类型。</param>
		void AddComponent(Type componentImplementation);
		
		/// <summary>
		/// 根据组件实现类型及组件接口类型向容器注册组件实现。
		/// </summary>
		/// <param name="componentImplementation">组件实现类型。</param>
		/// <param name="serviceType">组件接口类型。</param>
		void AddComponent(Type componentImplementation,Type serviceType);


		/// <summary>
		/// 根据组件实例向组件容器中注册组件。
		/// </summary>
		/// <param name="componentInstance">组件实例。</param>
		void AddComponentInstance(object componentInstance);
				
		/// <summary>
		/// 根据组件key及组件实现向组件容器中注册组件。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="componentInstance">组件实例。</param>
		void AddComponentInstance(string componentKey, object componentInstance);		

		/// <summary>
		/// 根据组件key、接口类型及组件实例向组件容器中注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="serviceType">组件接口类型。</param>
		/// <param name="componentInstance">组件实例。</param>
		void AddComponentInstance(string componentKey, Type serviceType, object componentInstance);

		/// <summary>
		/// 根据组件key、接口类型、组件实例及组件生存类型向组件容器中注册组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <param name="serviceType">组件接口类型。</param>
		/// <param name="componentInstance">组件实例。</param>
		/// <param name="lifestyleType"> 组件生命周期方式。</param>
		/// <param name="lifestyleParameters"> 组件生命周期相关参数,参数为一个字符串,其中由“:”分隔。</param>
		void AddComponentInstance(string componentKey, Type serviceType, object componentInstance,Lifecycle.LifestyleType lifestyleType,string lifestyleParameters);


		/// <summary>
		/// 根据组件key从组件容器中移除组件实现。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <returns></returns>
		void RemoveComponent(string componentKey);       

		/// <summary>
		/// 根据组件实例从组件容器中移除组件实现。
		/// </summary>
		/// <param name="componentInstance">组件实例。</param>
		/// <returns></returns>
		void RemoveComponent(object componentInstance);

        /// <summary>
        /// 根据组件key及组件实例从组件容器中移除组件实现。
        /// </summary>
        /// <param name="componentKey">组件key。</param>
        /// <param name="componentInstance">组件实例。</param>
        /// <returns></returns>
        void RemoveComponent(string componentKey, object componentInstance);

		/// <summary>
		/// 根据组件key判断组件容器是否含指定key的组件实例。
		/// </summary>
		/// <param name="componentKey">组件key。</param>
		/// <returns></returns>
		bool HasComponent(string componentKey );

		/// <summary>
		/// 根据组件实例判断组件容器是否含指定key的组件实例。
		/// </summary>
		/// <param name="componentInstance">组件实例。</param>
		/// <returns></returns>
		bool HasComponent(object componentInstance );

		/// <summary>
		/// 根据组件接口类型判断组件容器是否含指定key的组件实例。
		/// </summary>
		/// <param name="serviceType">组件接口类型。</param>
		/// <returns></returns>
		bool HasComponent( Type serviceType );

		/// <summary>
		/// 组件索引器,获取指定Key值的组件实例。
		/// </summary>
		object this[string key]
		{
			get;
		}

		/// <summary>
		/// 组件索引器,获取指定接口类型的组件实例。
		/// </summary>
		object this[Type key]
		{
			get;
		}


		/// <summary>
		/// 根据组件实例从组件容器中释放组件实例。
		/// </summary>
		/// <param name="componentInstance">组件实例。</param>
		void ReleaseComponent(object componentInstance );

		/// <summary>
		/// 根据组件Key从组件容器中释放组件实例。
		/// </summary>
		/// <param name="componentKey">组件Key。</param>
		void ReleaseComponent( string componentKey );

		/// <summary>
		/// 根据组件的key取得组件实例。
		/// </summary>
		/// <param name="componentKey">组件的key。</param>
		/// <returns>组件实例。</returns>
		object GetComponentInstance(string componentKey);

		/// <summary>
		/// 根据组件的类型取得组件实例。
		/// </summary>
		/// <param name="componentType">组件类型。</param>
		/// <returns>组件实例。</returns>
		object GetComponentInstance(Type componentType);

        /// <summary>
        /// 根据组件服务类型取得组件实例。
        /// </summary>
        /// <param name="serviceType">组件接口类型。</param>
        /// <returns>组件实例。</returns>
        object GetServiceComponentInstance(Type serviceType);

		/// <summary>
		/// 获取一个值,批示容器中所有的组件列表。
		/// </summary>
        IDictionary<string, object> ComponentInstances { get; }
		
		/// <summary>
		/// 根据组件类型取得组件实例列表。
		/// </summary>
		/// <param name="serviceType">组件接口类型。</param>
		/// <returns>组件实例列表。</returns>
		IList GetComponentInstances(Type serviceType);
		

		/// <summary>
		/// 获取一个值,该值批示组件容器中的所有组件适配器列表。
		/// </summary>
        IDictionary<string, IComponentAdapter> ComponentAdapters { get; }

		/// <summary>
		/// 根据组件key取得与组件相关的组件适配器。
		/// </summary>
		/// <param name="componentKey">组件的key。</param>
		/// <returns>指定组件的组件适配器。</returns>
		IComponentAdapter GetComponentAdapter(string componentKey);

		/// <summary>
		/// 根据组件类型取得与组件相关的组件适配器。
		/// </summary>
		/// <param name="componentType">组件类型。</param>
		/// <returns>指定组件类型的组件适配器。</returns>
		IComponentAdapter GetComponentAdapter(Type componentType);

		/// <summary>
		/// 根据组件类类型获取组件适配器列表。
		/// </summary>
		/// <param name="serviceType">组件接口类型。</param>
		/// <returns>指定组件类型的组件适配器列表。</returns>
        IDictionary<string, IComponentAdapter> GetComponentAdapters(Type serviceType);


		/// <summary>
		/// 获取一个值,该值批示组件容器中的所有组件生命周期管理器列表。
		/// </summary>
        IDictionary<string, ILifecycleManager> LifecycleManagers { get;}
		
		/// <summary>
		/// 根据组件key取得与组件相关的组件生命周期管理器。
		/// </summary>
		/// <param name="componentKey"> 组件的键。</param>
		/// <returns>指定组件键的生命周期管理器。</returns>
		Lifecycle.ILifecycleManager GetLifecycleManager(string componentKey);

		/// <summary>
		/// 根据组件实现类型取得与组件相关的组件生命周期管理器。
		/// </summary>
		/// <param name="componentType"> 组件的实现类型。</param>
		/// <returns>指定组件类型的生命周期管理器。</returns>
		Lifecycle.ILifecycleManager GetLifecycleManager(System.Type componentType);

		/// <summary>
		/// 根据组件接口类型取得与组件相关的组件生命周期管理器列表。
		/// </summary>
		/// <param name="serviceType"> 组件的接口类型。</param>
		/// <returns>指定组件类型的生命周期管理器。</returns>
        IDictionary<string, ILifecycleManager> GetLifecycleManagers(System.Type serviceType);

	}

IContext定义:

IContext	public interface IContext
	{
		/// <summary>
		/// 组件容器,获取系统上下文中的组件容器。
		/// </summary>
		EAS.Objects.IContainer Container { get;}

		/// <summary>
		/// 判定指定名称的组件是生存周期是否为Singleton模式。
		/// </summary>
		/// <param name="name">组件的名称。</param>
		/// <returns>组件的生存周期是否为Singleton模式,是则返回true,否则返回false。</returns>
		bool IsSingleton(string name);

		/// <summary>
		/// 根据组件名称获取指定组件的生命周期类型。
		/// </summary>
		/// <param name="name">组件的名称。</param>
		/// <returns>组件的生命周期类型。</returns>
		Objects.Lifecycle.LifestyleType GetLifestyleType(string name);

		/// <summary>
		/// 上下文中是否包含指定名称的组件实例。
		/// </summary>
		/// <param name="name">组件的名称。</param>
		/// <returns>是否包含特定的组件。包含则返回true,否则返回false。</returns>
		bool ContainsObject(string name);
		
		/// <summary>
		/// 上下文中是否包含指定类型的组件实例。
		/// </summary>
		/// <param name="type">组件接口类型。</param>
		/// <returns>是否包含特定的组件。包含则返回true,否则返回false。</returns>
		bool ContainsObject(System.Type type);

		/// <summary>
		/// 索引器,根据名称获取指定的组件实例。
		/// </summary>
		object this[string name] { get; }

		/// <summary>
		/// 根据组件的名称返回一个组件实例。
		/// </summary>
		/// <param name="name">组件的名称。</param>
		/// <returns>组件的实例。</returns>
		object GetObject(string name);

		/// <summary>
		/// 根据组件的类型返回一个组件实例。
		/// </summary>
		/// <param name="type">组件的类型。</param>
		/// <returns>组件的实例。</returns>
		object GetObject(System.Type type);

		/// <summary>
		/// 根据组件的名称返回组件实例的类型。
		/// </summary>
		/// <param name="name">组件名称。</param>
		/// <returns>组件类型。</returns>
		Type GetType(string name);

		/// <summary>
		/// 在容器中配置组件。
		/// </summary>
		/// <param name="target">要配置的组件目标对象。</param>
		void ConfigureObject(object target);

		/// <summary>
		/// 在容器中配置组件。
		/// </summary>
		/// <param name="name">组件名称。</param>
		void ConfigureObject(string name);

		/// <summary>
		/// 在容器中配置组件。
		/// </summary>
		/// <param name="target">要配置的组件目标对象。</param>
		/// <param name="name">组件名称。</param>
		void ConfigureObject(object target, string name);

		/// <summary>
		/// 在容器中配置组件。
		/// </summary>
		/// <param name="type">组件类型。</param>
		void ConfigureObject(System.Type type);

		/// <summary>
		/// 在容器中配置组件。
		/// </summary>		
		/// <param name="type">组件类型</param>
		/// <param name="name">组件名称。</param>
		void ConfigureObject(System.Type type,string name);
	}

 

  QQ群:15118502

链接:AgileEAS.NET应用开发平台介绍

AgileEAS.NET之敏捷并行开发方法

敏捷软件工程实验室

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
8月前
|
存储 开发框架 前端开发
前端框架EXT.NET Dotnet 3.5开发的实验室信息管理系统(LIMS)成品源码 B/S架构
发展历史:实验室信息管理系统(LIMS),就是指通过计算机网络技术对实验的各种信息进行管理的计算机软、硬件系统。也就是将计算机网络技术与现代的管理思想有机结合,利用数据处理技术、海量数据存储技术、宽带传输网络技术、自动化仪器分析技术,来对实验室的信息管理和质量控制等进行全方位管理的计算机软、硬件系统,以满足实验室管理上的各种目标(计划、控制、执行)。
72 1
|
4月前
|
Ubuntu 持续交付 API
如何使用 dotnet pack 打包 .NET 跨平台程序集?
`dotnet pack` 是 .NET Core 的 NuGet 包打包工具,用于将代码打包成 NuGet 包。通过命令 `dotnet pack` 可生成 `.nupkg` 文件。使用 `--include-symbols` 和 `--include-source` 选项可分别创建包含调试符号和源文件的包。默认情况下,`dotnet pack` 会先构建项目,可通过 `--no-build` 跳过构建。此外,还可以使用 `--output` 指定输出目录、`-c` 设置配置等。示例展示了创建类库项目并打包的过程。更多详情及命令选项,请参考官方文档。
254 11
|
7月前
|
开发框架 前端开发 .NET
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
集成于VS 2019,EXT.NET前端和ASP.NET后端,搭配MSSQL 2018数据库。系统覆盖样品管理、数据分析、报表和项目管理等实验室全流程。应用广泛,包括生产质检(如石化、制药)、环保监测、试验研究等领域。随着技术发展,现代LIMS还融合了临床、电子实验室笔记本和SaaS等功能,以满足复杂多样的实验室管理需求。
87 3
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
|
开发框架 监控 .NET
ASP.NET Dotnet LIMS实验室综合管理和质量监控系统源码
系统功能包括检测管理(合同管理、样品管理、样品收发管理、工作任务分配、检测结果登记、复核及审核、留样管理等)、报告管理(报告编制、审核、签发、打印等)、原始记录管理、仪器设备管理、物质试剂管理、文件管理、组织人员管理、标准管理、客户供应商管理、财务管理、查询统计等诸多模块为一体,组成一套完整的实验室综合管理和质量监控体系。
|
SQL 数据可视化 BI
十三、.net core(.NET 6)搭建ElasticSearch(ES)系列之dotnet操作ElasticSearch进行存取的方法
.net core操作ES进行读写数据操作在Package包项目下,新增NEST包。注意,包版本需要和使用的ES的版本保持一致,可以避免因为不兼容所导致的一些问题。例如我本机使用的ES版本是7.13版本,所以我安装的NEST包也是7.13版本:
882 0
十三、.net core(.NET 6)搭建ElasticSearch(ES)系列之dotnet操作ElasticSearch进行存取的方法
|
缓存 监控 Unix
.NET Core 跨平台资源监控库及dotnet tool小工具
.NET Core 跨平台资源监控库及dotnet tool小工具
507 0
|
监控 .NET 开发框架
4.3dotnet watch run「深入浅出ASP.NET Core系列」
原文:4.3dotnet watch run「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁、等公交,积少成多,水滴石穿,谢谢关注。 dotnet run的麻烦   如果您使用的是vs code进行跨平台开发,那么dotnet watch run对你的调试就是一把利器!我们先看下使用dotnet run的效果:      如视频所示,我们在vs code里面创建一个mvc项目,dotnet run后,启动调试,一切正常。
1405 0
|
监控 .NET C++
4.3dotnet watch run「深入浅出ASP.NET Core系列」
希望给你3-5分钟的碎片化学习,可能是坐地铁、等公交,积少成多,水滴石穿,谢谢关注。 dotnet run的麻烦   如果您使用的是vs code进行跨平台开发,那么dotnet watch run对你的调试就是一把利器!我们先看下使用dotnet run的效果:      如视频所示,我们在vs code里面创建一个mvc项目,dotnet run后,启动调试,一切正常。
1365 0
|
.NET 开发框架 开发工具
菜鸟入门【ASP.NET Core】7:WebHost的配置、 IHostEnvironment和 IApplicationLifetime介绍、dotnet watch run 和attach到进程调试
WebHost的配置 我们用vs2017新建一个空网站HelloCore 可以使用ConfigureAppConfiguration对配置进行更改,比如说添加jsonfile和commandline配置。
2464 0
|
.NET 开发框架 前端开发
[Asp.Net Core] 1. IIS中的 Asp.Net Core 和 dotnet watch
在基于传统的.NET Framework的Asp.Net Mvc的时候,本地开发环境中可以在IIS中建立一个站点,可以直接把站点的目录指向asp.net mvc的项目的根目录。然后build一下就可以在浏览器里面刷新到最新的修改了,也可以附加到w3wp的进程进行调试。
1567 0