返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

ABP模块系统

说了这么久,还没有详细说到abp框架,abp其实基于DDD(领域驱动设计)原则的细看分层如下:

再看我们项目解决方案如下:

JCmsErp.Application,应用层:进行展现层与领域层之间的协调,协调业务对象来执行特定的应用程序的任务。它不包含业务逻辑,主要包含一些模型,abp重要的数据传输DTO,包括数据库映射实体,前端视图模型转实体(Entity)对象,一个应用服务方法通常被认为是一个工作单元(Unit of Work),使用一种像AutoMapper这样的工具来进行实体与DTO之间的映射,前端参数传入有限性验证等等

JCmsErp.Core:领域层:领域层就是业务层,是一个项目的核心,所有业务规则都应该在领域层实现。包括业务对象和业务规则,这是应用程序的核心层。

实体(Entity):实体代表业务领域的数据和操作,在实践中,通过用来映射成数据库表。

仓储(Repository):仓储用来操作数据库进行数据存取。仓储接口在领域层定义,而仓储的实现类应该写在基础设施层。

领域服务(Domain service):当处理的业务规则跨越两个(及以上)实体时,应该写在领域服务方法里面。

领域事件(Domain Event): 在领域层某些特定情况发生时可以触发领域事件,并且在相应地方捕获并处理它们。 

工作单元(Unit of Work)工作单元是一种设计模式,用于维护一个由已经被修改(如增加、删除和更新等)的业务对象组成的列表。它负责协调这些业务对象的持久化工作及并发问题。

JCmsErp.EntityFramework:基础设施层:提供通用技术来支持更高的层。例如基础设施层的仓储(Repository)可通过ORM来实现数据库交互。当在领域层中为定义了仓储接口,应该在基础设施层中实现这些接口。可以使用ORM工具,例如EntityFramework或NHibernate。ABP的基类已经提供了对这两种ORM工具的支持。还有数据迁移等。

JCmsErp.Web:展现层:提供试图用于与用户实现交互操作.

JCmsErp.WebApi:这里在abp中主要是提供接口,可以是解决方案内部使用接口,可以是与移动端等其他端口连接的接口.

二,实体(Entity)

实体是DDD(领域驱动设计)的核心概念之一。Eirc Evans是这样描述的实体的:“它根本上不是通过属性定义的,而是通过一系列连续性和标识定义的”。因此,实体都有Id属性并且都存储到数据库中。一个实体一般会映射到数据库的一张表

abp中实体是派生于Entity类,先看一下我们在Core层新建的Users类

Users实体类,有人说这个实体为什么没有id,因为Users继承自Entity类,Entity类已经定义id,

它是该Entity类的 主键。因此,所有实体的主键名都是相同的,都是Id

Id(主键)的类型是可以改变的,默认是int(int32)的。如果你想将Id定义为其他类型,可以在<>内写,比如Guid,long也是可以的。

Entity类重写了等号运算符(==),可以轻松地检查两个实体是否相同了(实体的Id相同则认为它们相同)。它也定义了IsTransient方法来检测它是否有Id。

审计:

IHasCreationTime使得使用一个通用的属性来描述一个实体的“创建时间”信息成为可能。当实现了该接口的实体类插入到数据库中时,ABP会自动地将当前的时间设置给CreationTime。

ICreationAudited增加了CreatorUserId扩展了IHasCreationTime,当用户保存一个新的实体的时候,会自动把当前的id设置为CreatorUserId,还有类似的LastModificationTime也是一样。

当更新实体时,abp会自动为你设置这些属性。

软删除

软删除是将一个实体标记为已删除的通常使用的模式,而不是直接从数据库中删除。比如,你可能不想从数据库中硬删除一个User,因为它可能关联其他的表

ABP实现了开箱即用的软删除模式。当一个软删除实体被删除后,ABP检测到之后,会阻止删除,将IsDeleted设置为true并更新数据库中的实体。而且,它会自动地过滤数据库中软删除的实体,不会检索(select)它们。

如果使用了软删除,那么你可能想存储一些信息,比如何时删除以及谁删除了一个实体等等

在JCmsErp.Application创建一个Users文件夹,然后创建UserinfoDto,DTO是用于Core和 Web间的数据传输对象.有了实体了为什么还要DTO呢

1,DTO保证了层与层的分离,web层改变不影响core层,core做改变也不影响web.

2,数据保护,不然敏感或者不需要的数据暴露于web层,不被别人窥见如密码,银行账号,身份证等敏感信息

3,序列化,序列化集合,但是子集不序列化,当首次用到子集的时候才序列化.

4,惰性加载

5,DTO数据验证

6,abp还有一些扩展的接口,扩展性好,降低耦合度,使表现层和逻辑层之间耦合度降低.

这里Serializable就是支持序列化的标签,   [AutoMapFrom(typeof(Users))]是指和Users之间双向自动转化的标签,并不需要每个字段都去手动匹配.ABP提供了若干特性和扩展方法来定义映射。首先,要将Abp.AutoMapper nuget包添加到项目中。然后,AutoMap特性是双向映射方式, AutoMapFrom和 AutoMapTo是单向映射方式。最后,使用MapTo扩展方法将一个对象映射到另一个对象

ABP模块系统简介

ABP框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块。在通常情况下,一个程序集就可以看成是一个模块。在ABP框架中,一个模块通过一个类来定义,而这个类要继承自AbpModule。

模块系统当前专注于服务端而不是客户端。

如果学习过Orchard的朋友,应该知道module模块的强大了。模块的本质就是可重用性,你可以在任意的地方去调用,而且通过实现模块,你写的模块也可以给别人用。.net可以通过反射获取一个程序集中的类以及方法。

1.3.2 定义模块

Assembly程序集:Assembly是一个用来包含程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。最简单的理解就是:一个你自己写的类库生成的dll就可以看做是一个程序集,这个程序集可以包括很多类,类又包括很多方法等。

一个派生自 AbpModule 的类就是模块的定义。我们正在开发一个博客模块,该模块可以被使用在不同的应用程序中。最简单的模块定义示例如下:

public class MyBlogApplicationModule : AbpModule //定义
{
public override void Initialize() //初始化
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
//这行代码的写法基本上是不变的。它的作用是把当前程序集的特定类或接口注册到依赖注入容器中。
}
}

如果需要的话,模块类负责类的依赖注入(通常可以像上面一样做)。我们能配置应用程序和其它模块,添加新的功能到应用程序等等。

1.3.3 方法的生命周期

在一个应用中,ABP框架调用了Module模块的一些指定的方法来进行启动和关闭模块的操作。我们可以重载这些方法来完成我们自己的任务。

ABP框架通过依赖关系的顺序来调用这些方法,假如:模块A依赖于模块B,那么模块B要在模块A之前初始化,模块启动的方法顺序如下:

  1. PreInitialize-B
  • PreInitialize-A
  • Initialize-B
  • Initialize-A
  • PostInitialize-B
  • PostInitialize-A

下面是具体方法的说明:

PreInitialize

预初始化:当应用启动后,第一次运行会先调用这个方法。在初始化(Initialize)方法调用之前,该方法通常是用来配置框架以及其它模块。

在依赖注入注册之前,你可以在这个方法中指定你需要注入的自定义启动类。例如:加入你创建了某个符合约定的注册类,你应该使用 IocManager.AddConventionalRegisterer 方法在这里注册它。

Initialize

初始化:在这个方法中一般是来进行依赖注入的注册,一般我们通过IocManager.RegisterAssemblyByConvention这个方法来实现。如果你想实现自定义的依赖注入,那么请参考依赖注入的相关文档。

PostInitialize

提交初始化:最后一个方法,这个方法用来解析依赖关系。

Shutdown

关闭:当应用关闭以后,这个方法被调用。

1.3.4 模块依赖

Abp框架会自动解析模块之间的依赖关系,但是我们还是建议你通过重载GetDependencies方法来明确的声明依赖关系。

[DependsOn(typeof(MyBlogCoreModule))]//通过注解来定义依赖关系
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}

例如上面的代码,我们就声明了MyBlogApplicationModule和MyBlogCoreModule的依赖关系,MyBlogApplicationModule这个应用模块依赖于MyBlogCoreModule核心模块,并且,MyBlogCoreModule核心模块会在MyBlogApplicationModule模块之前进行初始化。

ABP可以从 startup module 递归的解析依赖关系,并按需初始化它们。最后初始化的模块是启动模块(startup module)。

1.3.5 插件模块

当模块从启动模块以及其依赖关系进行调查发现的时候,ABP也能够动态的加载其它指定模块。AbpBootstrapper 类定义了 PlugInSources 属性,我们能用该属性添加需要动态加载的模块。插件源可以是任何实现了 IPlugInSource 接口的类。FolderPlugInSource 类实现了该接口,它可以被用来加载指定文件夹下的程序集。

ASP.NET Core

ABP的ASP.NET Core模块也可以动态加载模块,你只需要在 Startup 类中使用已定义的扩展方法 AddAbp,如下所示:

services.AddAbp<MyStartupModule>(options =>
{
options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns"));
});

我们可以使用扩展方法 AddFolder 更方便的实现上述功能:

services.AddAbp<MyStartupModule>(options =>
{
options.PlugInSources.AddFolder(@"C:\MyPlugIns");
});

了解更多关于Startup类的信息,请查看 ASP.NET 文档

ASP.NET MVC,Web API

对于经典的ASP.NET MVC应用,我们可以在 global.asax 重写 Application_Start 方法来添加插件文件夹,如下所示:

public class MvcApplication : AbpWebApplication<MyStartupModule>
{
protected override void Application_Start(object sender, EventArgs e)
{
AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns");
//...
base.Application_Start(sender, e);
}
}

插件中的控制器

如果你的模块包括了MVC或者Web API控制器,ASP.NET不能发现这些控制器。为了克服这个问题,你可以在 global.asax 中添加代码来实现,如下所示:

using System.Web;
using Abp.PlugIns;
using Abp.Web;
using MyDemoApp.Web; [assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")] namespace MyDemoApp.Web
{
public class MvcApplication : AbpWebApplication<MyStartupModule>
{
} public static class PreStarter
{
public static void Start()
{
//...
MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\");
MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager();
}
}
}

Additional Assemblies

对于IAssemblyFinder和ITypeFinder的默认实现(这两个接口的实现被ABP用来在应用程序中发现指定的类)仅仅只用来查找模块程序集以及在这些程序集中所使用的类型。我们可以在我们的模块中重写 GetAdditionalAssemblies 方法来包含附加程序集。

1.3.6 自定义的模块方法

我们自己定义的模块中可能有方法被其他依赖于当前模块的模块调用,下面的例子,假设模块2依赖于模块1,并且想在预初始化的时候调用模块1的方法。这样,就把模块1注入到了模块2,因此,模块2就能调用模块1的方法了。

译者注:
ABP的模块系统与Orchard的模块有类似之处,但还是有比较大的差别。Orchard的框架修改了ASP.NET程序集的默认加载方式(模块的DLL没有放在Bin文件夹下,是放在WEB项目根文件夹下面的Modules文件夹下),实现了功能模块的热插拔,而ABP的模块程序集还是放在Bin文件夹下的,没有实现热插拔。

public class MyModule1 : AbpModule
{
public override void Initialize() //初始化模块
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());//这里,进行依赖注入的注册。
} public void MyModuleMethod1()
{
//这里写自定义的方法。
}
} [DependsOn(typeof(MyModule1))]
public class MyModule2 : AbpModule
{
private readonly MyModule1 _myModule1; public MyModule2(MyModule1 myModule1)
{
_myModule1 = myModule1;
} public override void PreInitialize()
{
_myModule1.MyModuleMethod1(); //调用MyModuleMethod1的方法。
} public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}

在这里,我们通过构造函数注入MyModule1到MyModule2,所以MyModule2能够调用MyModule1的自定义方法。当且仅当MyModule2依赖于MyModule1才是可能的。

1.3.7 模块配置

虽然自定义模块可以被用来配置模块,但是,作者建议使用启动配置来定义和配置模块。

1.3.8 模块生命周期

所有的模块类都被自动的注册为单例模式。

返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

ABP+AdminLTE+Bootstrap Table权限管理系统第三节--abp分层体系,实体相关及ABP模块系统的更多相关文章

  1. ABP+AdminLTE+Bootstrap Table权限管理系统第七节--登录逻辑及几种abp封装的Javascript函数库

    返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期         简介 经过前几节,我们已经解决数据库,模型,DTO,控制器和注入等问题.那么再来看一下登录逻辑.这 ...

  2. ABP+AdminLTE+Bootstrap Table权限管理系统第三节--abp分层体系及实体相关

    说了这么久,还没有详细说到abp框架,abp其实基于DDD(领域驱动设计)原则的细看分层如下: 再看我们项目解决方案如下: JCmsErp.Application,应用层:进行展现层与领域层之间的协调 ...

  3. ABP+AdminLTE+Bootstrap Table权限管理系统一期

       学而时习之,不亦说乎,温顾温知新,可以为师矣. 这也是算是一种学习的方法和态度吧,经常去学习和总结,在博客园看了很多大神的文章,写下一点对于ABP(ABP是“ASP.NET Boilerplat ...

  4. ABP+AdminLTE+Bootstrap Table权限管理系统第五节--WBEAPI及SwaggerUI

    一,Web API ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没 ...

  5. ABP+AdminLTE+Bootstrap Table权限管理系统第六节--abp控制器扩展及json封装

    一,控制器AbpController 说完了Swagger ui 我们再来说一下abp对控制器的处理和json的封装. 首先我们定义一个控制器,在新增控制器的时候,控制器会自动继承自AbpContro ...

  6. ABP+AdminLTE+Bootstrap Table权限管理系统第十一节--bootstrap table之用户管理列表

    这张开始bootstrap table,引入项目有两种方法,一种是直接去官网下载 地址:http://bootstrap-table.wenzhixin.net.cn/ 另一种是Nuget引入. 然后 ...

  7. ABP+AdminLTE+Bootstrap Table权限管理系统第十节--AdminLTE模板菜单处理

    上节我们把布局页,也有的临时的菜单,但是菜单不是应该动态加载的么?,所以我们这节来写菜单.首先我们看一下AdminLTE源码里面的菜单以及结构. <aside class="main- ...

  8. ABP+AdminLTE+Bootstrap Table权限管理系统第九节--AdminLTE模板页搭建

    AdminLTE 官网地址:https://adminlte.io/themes/AdminLTE/index2.html 首先去官网下载包下来,然后引入项目. 然后我们在web层添加区域Admin以 ...

  9. ABP+AdminLTE+Bootstrap Table权限管理系统第八节--ABP错误机制及AbpSession相关

    上一节我们讲到登录逻辑,我做的登录逻辑很简单的,我们来看一下abp module-zero里面的登录代码. #region Login / Logout public ActionResult Log ...

随机推荐

  1. drupal 2006 mysql server has gone away

    在开发一个cms drupal网站时遇到了如上图的错误,几经百度谷歌,都一致说需要修改mysql的配置 max_allowed_packet参数,但是由于我买的是虚拟主机,并没有权限修改. 本来已经放 ...

  2. 【redis专题(3)】命令语法介绍之link

    通过链表结构可以模仿队列结构与堆栈结构:关于队列结构和堆栈结构可以查看https://www.zybuluo.com/a5635268/note/290475 增 lpush key value1 v ...

  3. sql server自定义函数学习笔记

    sql server中函数分别有:表值函数.标量函数.聚合函数.系统函数.这些函数中除系统函数外其他函数都需要用户进行自定义. 一.表值函数 简单表值函数 创建 create function fu_ ...

  4. 实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

    记录一下,方便以后复制粘贴 // 方法一: Object.prototype.clone = function() { var o = this.constructor === Array ? [] ...

  5. WebSocket简单尝试

    System.Net.WebSockets.WebSocket 需要.NET 4.5,IIS8以上,Windows Server2008R2自带的IIS不支持,Windows8及Server2012以 ...

  6. Fedora 29 查看 rpm 包 依赖性 以 libconfig 为例

    查看依赖性方法:# rpmrepater会向用户显示已安装包的列表,你可以使用上/下箭头来滚动屏幕# 可以在指定包上使用"r"键来显示其依赖关系,循环在指定包上按下"r& ...

  7. Linux : Vim 使用与配置 (附 GitHub 自动化配置脚本)

    由于经常使用 vim 编辑配置文件,有时候也会进行使用vim 编写一些脚本和c/c++ 程序,所以配置一个常用的 vim 是很是必要的.这篇博文主要是记录vim使用和配置相关的一些知识点. 关于vim ...

  8. nginx配置基于域名、端口、IP的虚拟主机

    1.基于域名的虚拟主机: 绝大多数企业对外提供服务的网站使用的都是基于域名的主机,通过不同的域名区分不同的虚拟主机. 首先我们进入安装nginxd的目录下:/application/nginx-1.6 ...

  9. Win7系统system进程句柄数一直增加解决方案

    公司内部最近有个服务端的同事电脑句柄数一开机就一直增加 一台Windows7x64系统16G 其实物理内存使用情况在开机后并没有太大的变化,但虚拟内存占用明显在不停的增加. 我通过“任务管理器”一直也 ...

  10. 如何根据name和value选中radio [问题点数:40分,结帖人zzxap

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html>  <he ...