何老师的框架哲学(一)
1、如果一个Table的ID被别的Table做为外键,那么设计这个Table的类时,要加上 public virtual ICollection<别的类> 的定义。就是一条记录可能对应其他类的多条记录时候,在构造函数内加上其他类的ICollection。反过来如果一个Table引用了别的Table的ID做为外键,那么在类中也要加上别的类的引用,比如角色内加上 角色类型 public virtual RoleType RoleType { get; set; }
2、何老师发来的代码包含2个解决方案,一个是Applications(例子),一个是Util(框架)
我们先从简单的Applications开始
Applications.Presentation MVC项目
Applications.Presentation.Extensions 类库项目
Applications.Services应用服务层
03-Domains是领域层,里边四个项目分别是划分的功能模块,每个功能模块包含Enums(枚举)、Models(领域实体)、Queries(查询实体)、Repositories(仓储)、Services(领域服务)几个文件夹
Applications.Datas 包含Repositories仓储(数据访问层 ) Mappings映射(领域实体到数据表)
Applications.Infrastructure.Security(安全身份认证功能)
下边分别介绍没层中几个重要的类和接口
1、Applications.Presentation
Areas是MVC的几个区,每个区都有Controllers文件夹,放控制器类
一般控制器类都是继承Controller类,项目中增加了几个Controller类派生类来封装更多功能,方便代码复用
— MvcControllerBase(控制器基类):派生于Controller类。其增加了日志接口成员、object转Json字符串,返回类型Json字符串的ActionResult(响应结果) :
{ 自定义了返回类型为ActionResult的三个方法:两个Ok,一个Fail;
return new Result( StateCode.Ok, message, data ) 这里的Result 派生于 ContentResult类, ContentResult派生于 ActionResult;
Result类有一个ToString()方法,输出Json类型字符串;重写了ExecuteResult方法 }
— EasyUiControllerBase(EasyUi控制器基类):派生于MvcControllerBase类。类中实现了几种不同的ActionResult(响应结果)的输出方式.
输出结果继承于ResultBase基类,这个类有一个GetResult()函数,可以返回ActionResult, return new ContentResult { Content = ToString() };
后边由ResultBase基类派生的类,只需要自己重写ToString()方法就可以在调用基类GetResult()函数时候,返回不同方式的字符串了.
a、DataGridResult(DataGrid输出结果) 类派生于ResultBase,在EasyUiControllerBase类中ToDataGridResult<T>函数返回DataGridResult,其输出内容供DataGrid使用.
b、TreeResult(树结果类)派生于ResultBase类,树节点实现了ITreeNode接口,在EasyUiControllerBase类中实现了ToTreeResult(转换为Tree输出结果)和ToTreeGridResult(转换为TreeGrid输出结果)两种方式的输出
c、TreeGridResult(树型表格输出结果类)派生于ResultBase类,这里当totalCount是-1时候输出TreeResult,多行时候输出DataGridResult
d、何老师对EasyUi中网页标签属性进行了封装,这里需要介绍几个类,这几个类的目的是能通过C#代码返回EasyUi的网页内容字符串(非ActionResult),每个类都有GetResult()把对象内容变成网页代码输出,同时重载了ToString()函数,调用GetResult()函数 数型都是对树节点ITreeNode接口的操作
IAttributeNode(属性节点接口),它有GetResult()和GetValue()两个函数实现属性字符串的输出。有两个类实现了这个接口;AttributeListNode类输出后的格式是 :a;b;c;d;NameValuesAttributeNode类,GetValue()输出后的格式是:a;b;c;d GetResult()输出的格式是name="1;2;3" ,重载了ToString()函数调用GetResult()。例子:style="color:red;height:8px;"
AttributeBuilder(属性生成器类)这里有一个属性节点集合 private readonly Dictionary<string, IAttributeNode> _nodes; 调用的是IAttributeNode接口
AttributeBuilder类中多种对_nodes的操作,最后输出通过GetResult()输出属性集合合并后的字符串,重载ToString()函数调用GetResult()函数
同时实现class,style的增删改,添加data-属性,使用JsonAttributeBuilder类实现data-options属性的增删改
JsonAttributeBuilder(Json属性生成器类)这个类有一个成员AttributeBuilder _builder; _builder = new AttributeBuilder( ":","," ); 分隔符: 节点分隔符,利用AttributeBuilder类实现增删改,GetResult()进行输出, GetJson() 可以获取Json格式字符串
e、针对EasyUi的控件,做了一些封装,以下是一些基类和派生类
IOption(控件顶级接口)这个接口有Width、Height、AddAttribute、AddStyle、AddClass、AddDataOption、Margin、Padding几个函数定义,函数返回值都是控件本身
OptionBase(选项基类)继承IOption接口,有属性生成器EasyUiAttributeBuilder _builder; 这里的EasyUiAttributeBuilder继承AttributeBuilder类,使用这个类实现了大部分属性的增删改功能,增加了日志接口、通过函数GetOptions()实现了属性的输出。
ComponentBase(基组件类)派生于OptionBase类,实现IComponent接口,组件类增加了成员Id,id也是属性的一部分,控件后还能加Html.定义了虚方法GetResult()输出结果,以后的派生类都需要重写这个输出方法
ContainerBase(容器基类)派生于OptionBase类,实现IContainer接口,GetBeginResult() 方法是输出div标签内容字符串(包含<div>...</div>)
TextBox(文本框类)派生于ComponentBase类,实现ITextBox接口,增加了验证器类Validator _validator; 直接增加属性"easyui-textbox",定义了设置Name、Prompt、Value、Password()、MultiLine、Disable、ReadOnly、Editable、Icon(文本图标)、Button、OnChange、Delay、TipPosition、NoValidate、Required、mail()、MobilePhone()、ValidateUrl()、Length、MaxLength、MinLength、Remote、EqualTo、Max、Min、Range等;重写GetResult() 输出结果
Combo(组合控件类)派生于TextBox,实现了ICombo接口,增加了PanelHeight的设置
Combox(组合框类)派生于Combo类,实现了ICombox接口,组合框选项List<ComboxItem> _items;重写了一些方法,重写了GetResult(),使输出可以渲染为input或者select 下边我们在回到EasyUiControllerBase类
ActionResult ToComboxResult( IEnumerable<ComboxItem> items ) 输出Combox.ToJson( items )
SetPage( IPager query )方法可以设置分页的一些参数
EasyUiControllerBase是控制器的基类,他可以输出各种EasyUi元素代码;以前实现功能是多个函数之间的调用,现在用类进行了封装,就是把相关的函数包装成一个类的标签进行调用,调用时候可以直接引用,也可以继承后进行调用,类的使用是函数调用时候有了包装和层次,代码的世界里每个类都是一个人,他们有各自的特点,他们通过传承形成帮会 ,代码世界就是几个帮派之间的鏖战(这段可以忽略)。
下边在看下EasyUiControllerBase的几个派生类
—PermissionControllerBase(权限控制器类派生于EasyUiControllerBase) 此类有一个函数RenderPartialViewToString ,可以将PartialView输出为字符串 return RenderPartialViewToString( this, "Dialogs/Parts/CheckboxModel", model );
—QueryControllerBase(查询控制器类,派生于PermissionControllerBase)这个类增加了两个泛型,TDto(数据传输对象),TQuery(查询实体),同时在构造函数中引用了参数 IApplicationService(应用服务接口),这个很强大,可以直接调用应用层的所有功能。以后每个页面的Controller都从这个加强版的控制器继承,调用起来方便的很。这个类增加了一个ConvertQueryResult虚方法,以后可能会重写这个方法;增加了两个根据查询实体获得ActionResult的函数Query、PagerQuery或者ToDataGridResult函数返回值。
IApplicationService(应用服务接口)是框架内的接口,ApplicationServiceBase类实现了这个接口public abstract class ApplicationServiceBase<TEntity, TDto, TQuery, TKey> : IApplicationService<TDto, TQuery>
a、构造函数有两个参数,一个是工作单元接口IUnitOfWork,一个是仓储接口IRepository;增加了成员日志接口和日志添加写入函数AddLog、WriteLog
b、增加了虚拟方法,ToDto、ToEntity
c、通过仓储接口IRepository实现了如下功能:GetAll(获得全部Dto)、GetById(通过编号获得Dto)、GetByIds(通过编号列表获得Dto)
下边有必要把查询有关的接口和对象介绍下:
ICriteria接口(查询条件顶级接口)—只有一个Expression<Func<TEntity, bool>> GetPredicate(); 方法,获取查询条件
IQueryBase接口(查询对象接口)派生于ICriteria接口,只有2个成员string GetOrderBy();(获取排序) IPager GetPager();(获取分页)
IQuery接口(查询对象接口)派生于IQueryBase接口,具体实现看下边
Query(查询对象类)继承IQuery接口,查询对象构造函数public Query( IQueryEntity queryEntity ) ,这里的 IQueryEntity是查询实体结果接口,这样就把查询对象和查询实体的结果联系起来了。查询对象是一堆查询条件的组合,查询实体是查询的结果的展示。
暂时打断下,介绍下查询实体
IPagerBase(分页基接口)—只有三个成员Page(页数,即第几页,从1开始)、PageSize(每页显示行数)、TotalCount(总行数)
IPager(分页接口)—派生于IPagerBase接口GetPageCount()(获取总页数)、GetSkipCount(获取跳过的行数)、Order(排序条件)、GetStartNumber(获取起始行数)、GetEndNumber(获取结束行数)
IQueryEntity(查询实体结果接口)—派生于IPager接口,只有一个成员Keyword(搜索关键字)
StateDescription(状态描述)这个状态描述类是一个顶层的类,功能也很简单,添加字符串或者键值对字符串最后重写ToString函数实现输出,还带着一个钩子方法AddDescriptions,可以让大家添加补充描述内容,这个类只有2个基类继承,一个是Pager分页类,一个是领域层顶级基类DomainBase,下边我们介绍Pager分页类
Pager(分页基类)继承于StateDescription类,实现了IPager接口和IPagerBase接口,有两个构造函数获得信息,重写了AddDescriptions添加描述函数
QueryEntityBase(查询实体结果类)其实就是查询到的实体内容,上边Query(查询对象类)都是对Dto操作,他们之间应该也有一个装换。这个类派生于Pager(分页基类),实现了IQueryEntity(查询实体结果接口),重写了AddDescriptions描述函数,这个类就是Application领域层中的查询实体的顶级类了。这个类还派生了一个树型查询实体TreeQueryBase,我们后边在介绍。
PagerQuery(分页查询类)派生于List类,实现了IPagerBase接口,PagerList<TDto> PagerQuery( TQuery queryEntity )实现通过查询实体,获得分页后的Dto分页内容
d、Query(通过查询实体获得Dto)public virtual List<TDto> Query( TQuery queryEntity ) 这个函数的参数queryEntity是查询实体,实现了IQueryEntity接口,返回结果是Dto,查询实体肯定是带着一些参数的,每个聚合根都有一个查询实体,他的成员都是可空的
函数内容 : var query = CreateQuery( queryEntity );var queryable = Query( query );每个聚合根的应用服务都要重写这个CreateQuery函数 protected abstract IQueryBase<TEntity> CreateQuery( TQuery queryEntity ); 参数近来是查询实体,返回值是IQueryBase,这个IQueryBase是查询对象实现的接口,通过Query类接收一个查询实体,返回一个规约,这个规约最后变成一些lambda表达式,运行后获得var queryable就是查询后的实体内容列表了
简单的说就是查询实体带着参数过来,通过CreateQuery函数,创建Query对象,这个Query对象构造函数参数就是查询实体,然后在CreateQuery函数内,把查询实体的参数合并成一个总的lambda表达式,然后去对应的仓储运行获得实体查询结果。
以上可以看到应用层基类ApplicationServiceBase类实现了Dto的查询和日志写入,后边实现创建Dto,保存Dto,可能还有删除DTO,大家可以看到虽然框架代码比较复杂,但是总的来说都是围绕着增删改查来进行的,框架的目的就是让大家更加规范的操作数据的增删改查。下边看ApplicationServiceBase类剩下的几个函数
public virtual void Save( TDto dto )保存Dto 保存时判断是非新增实体或者修改实体
public virtual void Delete( string ids ) 删除实体
后边继续介绍这个QueryControllerBase类,它是mvc中使用的控制器类的上级类,这个类叫查询控制器,下边两个函数都是获得查询结果的
public virtual ActionResult Query( TQuery query ) 是不是很熟悉? 传入查询实体,使用的应用服务 Service.Query获得Dto,然后用上级类EasyUiControllerBase中的
protected ActionResult ToDataGridResult<T>( IList<T> data, int totalCount = 0 ) 返回查询结果
public virtual ActionResult PagerQuery( TQuery query ) 和上边一样,使用Service.PagerQuery获得分页Dto,输出结果,且提前设置了分页SetPage( query );
protected virtual IEnumerable<dynamic> ConvertQueryResult( List<TDto> result ) 这里增加了包装,这样到运行时才进行解析
—FormControllerBase(表单控制器,派生于QueryControllerBase类)这里的也有一个泛型TDto,不过他约束于DtoBase,DtoBase类是数据传输对象Dto的基类,成员有两个,一个是Id,一个是Validate()
他的构造函数也是有一个应用层服务接口
public virtual PartialViewResult Add 获取新增表单 这应该是新增一个Dto
public virtual PartialViewResult Edit( string id ) 编辑Dto
public virtual PartialViewResult Detail( string id ) 查看Dto
public virtual ActionResult Save( TDto dto ) 保存Dto
public virtual ActionResult Delete( string ids ) 删除Dto
return Ok( R.SaveSuccess ); 这里的R是资源文件中的定义文字,都在R.resx中
—GridControllerBase(表格控制器类,派生于QueryControllerBase类)它的应用层服务接口是IBatchService,派生于IApplicationService接口,增加了一个成员List<TDto> Save( List<TDto> addList, List<TDto> updateList, List<TDto> deleteList );
BatchServiceBase类派生于ApplicationServiceBase类,并且实现IBatchService接口 实现批量增改删操作
GridControllerBase类的public virtual ActionResult Save( string addList, string updateList, string deleteList )函数,把字符串换成Dto列表,然后调用BatchServiceBase类的Save函数
public virtual ActionResult New( string parentId ) 这个函数创建新实体,好像是为下一个派生类做功能
—TreeGridControllerBase(树型表格控制器类,派生于GridControllerBase类)这里的泛型TQuery约束于ITreeQuery ;TDto约束于ITreeNode,应用层服务接口调用的也是ITreeService,下边看看带上Tree后有什么变化
先看简单的ITreeNode(树节点接口)接口成员有:Id(标识)、ParentId(父标识)、Path(路径)、Level(级数)、State(状态)、List<ITreeNode> Children(子节点集合)
这个接口被两个类实现了,一个是TreeNode(树节点类) ,一个是TreeDtoBase(树型数据传输对象实现),他们三个都位于同一个命名空间Util.Ui.Trees
TreeNode(树节点类)这个类有[DataContract]、[DataMember]标签,代表可以被json序列化输出的;TreeNode类除了有ITreeNode接口成员外,还增加了几个成员,Text(文本)、Icon(图标)、Checked(是否选中)、Attributes(自定义扩展属性) [Json( PropertyName = "checked", NullValueHandling = NullValueHandling.Ignore )] 这里的属性等序列成Json后会变成checked:true
TreeDtoBase(树型数据Dto传输对象类),派生于DtoBase(数据传输对象基类),增加了成员的Required、Display等属性描述;新增成员有:Enabled(启用)、SortId(排序号)
ITreeQuery(树型查询实体接口,派生于IQueryEntity接口) 成员有:ParentId(父编号)、Level(级数)、Path(路径)、Enabled(启用)、IsEmpty(查询参数是否全部为空)
TreeQueryBase(树型实体查询参数类,派生于上边的查询实体基类QueryEntityBase类,实现了ITreeQuery接口)实现了IsEmpty()函数;重写了protected override void AddDescriptions()
ITreeEntity(树型实体接口,派生于IAggregateRoot接口)成员主要有:Parent(父对象)、ParentId(父编号)、Level(级数)、SortId(排序号)、Path(路径)、Enabled(启用)、InitPath()(初始化路径)、GetParentIdsFromPath(从路径中获取所有上级节点编号)
TreeEntityBase(领域层树型实体基类,派生于AggregateRoot类,实现了ITreeEntity接口),构造函数有三个参数TreeEntityBase( TKey id,string path,int level )
InitPath(初始化路径) 顶级默认Level = 1;Path=Id+","; 或者Level = parent.Level + 1;Path = string.Format( "{0}{1},", parent.Path, Id );
实现了GetParentIdsFromPath方法
ITreeService(树型实体批量操作服务,派生于IBatchService接口)这个接口增加了几个方法
TreeServiceBase(树型实体批量操作服务类,派生于BatchServiceBase类,实现了ITreeService接口)
public abstract class TreeServiceBase<TEntity, TDto, TQuery, TKey, TParentId> : BatchServiceBase<TEntity, TDto, TQuery, TKey>, ITreeService<TDto, TQuery>
where TEntity : class, IAggregateRoot<TEntity, TKey>, ITreeEntity<TEntity, TKey, TParentId>, new()
where TDto : IDto, new()
where TQuery : ITreeQuery<TParentId>
这里TEntity是实现ITreeEntity的实体,TQuery是实现ITreeQuery接口的查询实体
public List<string> GetParentIdsFromPath( TDto dto ) 调用领域实体内函数GetParentIdsFromPath,获得从路径中获取所有上级节点编号
protected virtual List<TEntity> GetAllChilds( TEntity parent ) 获得全部下级实体 调用仓储实现
protected virtual List<TEntity> GetRoots() 获得根节点
public virtual TDto Create( string parentId ) 创建实体
public virtual List<TDto> Enable( string ids ) 启用
public virtual List<TDto> Disable( string ids ) 冻结
public void FixPath() 修正路径
reeServiceBase<TEntity, TDto, TQuery> : TreeServiceBase<TEntity, TDto, TQuery, Guid, Guid?> 又重载了三个函数
protected override int GetSortId( Guid? parentId ) 获取排序号
protected override List<TEntity> GetChilds( TEntity parent ) 获取直接下级
protected override List<TEntity> GetRoots() 获取根节点
现在我们继续看TreeGridControllerBase类,突然发现从QueryControllerBase<TDto, TQuery>开始引入了 IApplicationService<TDto, TQuery>,一直到派生的 FormControllerBase<TDto, TQuery>,GridControllerBase<TDto, TQuery>,IBatchService<TDto, TQuery>,TreeGridControllerBase<TDto, TQuery>,ITreeService<TDto, TQuery>,他们都属于表现层,调用的是应用层的接口,里边的泛型只有TDto(数据传输对象)TQuery(查询实体,这个上边表示有误,这个实体其实就是平时查询时候,输入的一堆查询条件变化的),这些都是表现层的内容。
这些接口IApplicationService,IBatchService,ITreeService他们都是在应用层项目Applications.Services来实现的,当然对于一些框架基类,是放在框架Applications中实现了,我们看下顶级应用层类 public abstract class ApplicationServiceBase<TEntity, TDto, TQuery, TKey> : IApplicationService<TDto, TQuery> 这里出现泛型TEntity(领域实体)、TKey(实体标识类型)这些都是领域层的内容了,在他的构造函数中也出现了IUnitOfWork(工作单元接口)、 IRepository(仓储接口)直接调用的就是领域层内容了,这个程序的层次清晰的出现在我们面前。
protected override ActionResult Ok 重写了Ok函数
public override ActionResult New( string parentId ) 获取新实体
public override ActionResult Query( TQuery query )查询
public virtual ActionResult Enable( string ids ) 启用
public virtual ActionResult Disable( string ids )禁用
上边介绍了控制器类的派生类,下边开始以Commons/Area 中的内容为主做分析
表现层
Areas/Commons/Controllers /AreaController.cs(area的控制器)
Areas/Commons/Models(这里因为调用了应用层接口,这个文件夹内很多是空的)
Areas/Commons/Views/Area/Index.cshtml (area主页视图)
Areas/Commons/Views/Area/Parts/QueryForm.cshtml (查询分部视图)
Applications.Presentation.Extensions (表现层扩展)
/Commons/AreaControl.cs(地区控件类)
应用服务层(Applications.Services)
/Contracts/Commons/IAreaService.cs(area应用服务层接口,供表现层的控制类调用)
/Dtos/Commons/AreaDto.cs(area数据传输对象)
/Dtos/Commons/AreaDtoExtension.cs(area的Dto的扩展,主要是两个函数ToEntity、ToDto)
/Impl/Commons/AreaService.cs(应用层接口的实现)
领域层(领域层把每个功能模块分成了不同的项目 01-Applications.Domains.Commons项目中包含area的操作)
/Enums(这里一般放本项目中的枚举对象)
/Factories(这里放工厂类)
/Models/Area.cs(area部分类,领域实体,这里一般放实体内部操作的一些函数)
/Models/Area.Base.cs(area部分类,领域实体,主要放属性,重载了AddDescriptions(添加描述函数)、AddChanges(添加属性变更列表函数))
/Queries/AreaQuery.cs (area查询实体,主要接收查询参数,在表现层用的比较多)
/Repositories/IAreaRepository.cs(仓储接口,在应用层服务的构造函数中,和工作单元被一起传入)
/Services(领域服务层,这里放领域服务的类)
数据层(Applications.Datas)
/Mappings/Commons/AreaMap.cs(地区映射配置,里边MapTable(映射表)、MapProperties(映射属性)、MapAssociations(映射导航属性,如果有关联的表,在这里都有内容))
/Repositories/Commons/AreaRepository.cs(area仓储的实现,派生于RepositoryBase<Area>类,实现了IAreaRepository接口,这里一般没有内容,如果在其接口中有需要实现的功能函数,也需要在这里进行实现)
以上是对一个表进行操作需要的文件,感觉文件数量比过程式的编程要多很多呢,假如代码量相同的情况下,这么多文件每个文件分摊的代码量肯定会少,作坊式编程中每个文件、每个函数代码那是非常大的。也许这就是工厂和作坊的区别了,首先是地方大,可放置代码的文件多。只要规范操作,生产产品的效率那是杠杠的,另外软件产品不适一次性的,对于需要经常改动的软件产品,这种干净整洁的厂房是非常适合软件生产的。下边继续介绍area操作
/Impl/Commons/AreaService.cs(应用层接口的实现),以下是其实现的几个函数
—public override AreaDto Create( string parentId ) 重写了Create函数,调用上级TreeServiceBase类的Create方法,先创建一个Area实体,并且给ParentId、SortId赋值,然后转换成Dto,给Id赋值,最后设置Dto的Enabled=true,然后返回这个新创建的Dto.如果不是Tree范围的应用层服务,直接调用ApplicationServiceBase基类中的Create函数创建新Dto.另外DictionaryService中也重写了Create函数,除了给以上属性赋值,还给其独有的CreationTime属性赋值
—protected override IQueryBase<Area> CreateQuery( AreaQuery param ) 重写CreateQuery,参数是查询实体,返回IQueryBase接口,这个接口是查询对象实现的,就是返回一堆lambda表达式。然后接着在基类ApplicationServiceBase中,利用这些查询对象(一堆lambda表达式)通过仓储的Query函数,返回查询结果(实体List)
基类ApplicationServiceBase中CreateQuery是虚拟方法,每个聚合根的应用层服务都需要重写这个方法。
TreeCriteria(树型实体查询条件类),Filter( new TreeCriteria<Area>( param ) ) 自动对Level、Path、Enabled、ParentId生成查询Lambda语言And组合,查询前先过滤下,后边就是用查询对象结合传过来的查询实体,获得完整的查询语句了。
—public List<AreaDto> Load( Guid? parentId ) 加载地区数据 查询指定parentId的列表,自己创建一个AreaQuery,然后调用基类Query就可以了
TreeQueryBase(树型实体查询参数类,派生于QueryEntityBase类)是领域层树型查询实体的基类
TreeEntityBase(树型实体类,派生于AggregateRoot类)是领域层树型实体的基类
一个小发现:
表现层Controllers文件夹是控制器类,控制器类的构造函数一般有一个参数,是一个应用服务层的接口
特殊点的IconController,他的构造函数有2个参数,一个是自己的应用服务层接口,一个是IIconCategoryService的接口
表现层一般是调用应用服务层的接口
在应用服务层Impl目录下是应用层类的实现
这些实现类的构造函数一般有两个参数,一个是工作单元,一个是其仓储的接口
特殊点的IconService,他的构造函数有三个参数,一个是工作单元,一个是其仓储的接口,一个是领域服务中的一个借口IIconManager
SystemConfigService,多了一个ISystemConfigCategoryService的接口
CustomerService,多了一个IUserRepository接口,一个领域服务的ICustomerUserManager接口
EmployeeService,多了应用服务层的两个接口IOrganizationCategoryService,IOrganizationService,领域服务中的一个接口IEmployeeUserManager,和一个仓储接口IUserRepository
OrganizationCategoryService,多了一个领域服务中的IEmployeeUserManager接口
OrganizationService,多了一个应用服务层的IOrganizationCategoryService接口,一个领域服务层的IEmployeeUserManager接口
OnlineUserService,多了领域服务中的IOnlineManager接口,领域层中的IUserRepository,ICustomerRepository接口
ResourceService,多了应用服务层的IApplicationService,领域服务中的IRolePermissionManager接口
RoleService,多了应用服务层的IRoleTypeService,ITenantService接口,领域服务层的IRolePermissionManager,IRoleUserManager接口
SystemService,没有自己的仓储接口,调用的是IApplicationRepository,多了IResourceRepository,ILoginLogRepository,ITenantRepository,IEmployeeRepository,IUserContext,ICustomerRepository接口,领域服务曾的ILoginManager,IOnlineManager两个接口
TenantService,多了IEmployeeRepository,IUserRepository两个接口,一个领域服务层接口IEmployeeUserManager
UserService,多了IRoleUserManager接口
应用服务层,都是调用的领域层,或者本层其他聚合的
IOC的应用,随时创建接口
private IApplicationUnitOfWork _unitOfWork;
_unitOfWork = Ioc.Create<IApplicationUnitOfWork>();
private IApplicationRepository _applicationRepository;
applicationRepository = Ioc.Create<IApplicationRepository>();
调用时候直接用接口,不需要管实例化时候的构造函数参数了 ,如果直接实例化,万一有参数,是不是每个参数都要实例化? 这些都交给IOC处理去了