ABP架构学习系列三:手工搭建ABP框架

  由于公司的项目才接触到ABP这个框架,当时就觉得高大上,什么IOC、AOP、ddd各种专业词汇让人激情 澎湃,但在使用过程中碰到了许多坑,可能也许是没有去看源码导致的,但工作确实没有那么多时间让人去慢慢研究。很久之前想手动搭建这个框架了,但是各种理由,你懂的。但是要在技术上得到大的提升就得静的下心去研究,学到大神的思想和精髓,运用到实际中去,才能去体验更开阔的天地。

  本文以创建博客为思路,一步步构建整个项目,在摸索中进步,也希望能够帮助到有需要的人。

一、基础架构

  第一部分主要是搭建好整个项目的骨架,连通各个项目

  创建MVC5项目(ZmBlog.Web),手动引入Abp、Abp.Web、Abp.Web.Mvc、Abp.Web.Api

  详情请看上一篇第一部分:http://www.cnblogs.com/xcsn/p/7941541.html

  接下来,继续创建其他类库ZmBlog.Core、ZmBlog.Infrastructure、ZmBlog.Application。

二、ZmBlog.Core

  ZmBlog.Core是DDD的核心,实体、领域服务、事件等一般都写在这里,同时也定义了仓储的接口,但实现放在基础设施层。

首先,添加类ZmBlogCoreModule,如下

namespace ZmBlog.Core
{
    public class ZmBlogCoreModule:AbpModule
    {
        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        }
    }
}

ZmBlogCoreModule必须依赖于AbpModule,ZmBlogCoreModule是自定义模块第一个启动的,另外,ZmBlogCoreModule启动之前,abp会先启用内部的AbpKernelModule。

AbpKernelModule类是Abp框架自己的Module,它也跟所有其他的Module一样继承自AbpModule,重写PreInitialize,Initialize,PostInitialize三个主要成员。

更详细的请参考:https://www.cnblogs.com/Azula/archive/2015/11/23/4989157.html

现在,定义一个实体文章分类Category,继承自Entity<TPrimaryKey>

    public class Category: Entity<string>
    {
        public Category()
        {
            Id = Guid.NewGuid().ToString();
        }
        /// <summary>
        /// 类别名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 状态(0隐藏1显示)
        /// </summary>
        public int Status { get; set; }
    }

以下是Entity<TPrimaryKey>的成员,其中定义了主键Id(可重写)

接着,添加一个仓储接口ICategoryRepository

public interface ICategoryRepository : IRepository<Category,string>{}

另外,还可以添加领域服务ICategoryDomainService、CategoryDomainService,对于业务简单的模块,可以去掉领域服务,直接在应用层处理。

public interface ICategoryDomainService:IDomainService{}

public class CategoryDomainService : DomainService, ICategoryDomainService{}

三、ZmBlog.Infrastructure

1.定义模块

创建一个模块ZmBlogDataModule,依赖模块AbpEntityFrameworkModule会自动注册了所有仓储接口

[DependsOn(typeof(ZmBlogCoreModule),typeof(AbpEntityFrameworkModule))]
    public class ZmBlogDataModule : AbpModule
    {
        public override void Initialize()
        {
             IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        }
    }

2.使用EF作为orm

使用以下命令引入包

Install-Package EntityFramework -Version 6.1.3

Install-Package Castle.Windsor -Version 3.3.0

(1)创建ZmBlogDbContext

 public class ZmBlogDbContext: AbpDbContext
    {
        public ZmBlogDbContext()
            : base("DefaultConnection")
        {
        }

        public ZmBlogDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString)
        {
        }

        //This constructor is used in tests
        public ZmBlogDbContext(DbConnection connection)
            : base(connection, true)
        {
        }

        public DbSet<Category> Categorys { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

            modelBuilder.Configurations.Add(new CategoryCfg());//使用独立配置 

        }
    } 

DefaultConnection是连接字符串名称,在web项目添加或修改如下

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=ZmBlogDb;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

CategoryCfg是对实体类型的配置,如设置Id为主键

public class CategoryCfg: EntityTypeConfiguration<Category>
    {
        public CategoryCfg()
        {
            HasKey(s => s.Id);
        }
    }

(2)使用codefirst模式

1.启用迁移

启用:Enable-Migrations

自动生成配置文件:Configuration.cs

2.创建迁移

add-migration AddCategory

自动生成迁移文件:201712040256502_AddCategory

3.执行迁移

update-database -vebose

自动生成数据库ZmBlogDb、迁移记录表__MigrationHistory、表Categories

(3)实现仓储

基础类BaseRepository,继承实现增删改查

public  abstract  class BaseRepository<TEntity, TPrimaryKey> :EfRepositoryBase<ZmBlogDbContext,TEntity,TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey>
    {
        protected BaseRepository(IDbContextProvider<ZmBlogDbContext> dbContextProvider)
            : base(dbContextProvider)
        {

        }

        //add common methods for all repositories
    }
    public abstract class BaseRepository<TEntity> : BaseRepository<TEntity, string>
        where TEntity : class, IEntity<string>
    {
        protected BaseRepository(IDbContextProvider<ZmBlogDbContext> dbContextProvider)
            : base(dbContextProvider)
        {

        }

        //do not add any method here, add to the class above (since this inherits it)
    }

自定义的实现类,如下

 public class CategoryRepository : BaseRepository<Category, string>, ICategoryRepository
    {
        public CategoryRepository(IDbContextProvider<ZmBlogDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }
    }

四、ZmBlog.Application

1.添加模块

添加模块 ZmBlogApplicationModule

namespace ZmBlog.Application
{
    [DependsOn(typeof(ZmBlogCoreModule), typeof(ZmBlogDataModule))]
    public class ZmBlogApplicationModule:AbpModule
    {
        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        }
    }
}

2.创建服务

在项目下添加文件夹Categories,然后添加服务接口和实现类,如

ICategoryApp

public interface ICategoryApp:IApplicationService
    {
        string GetCategoryName(string id);
    } 

CategoryApp

namespace ZmBlog.Application.Categories
{
    public class CategoryApp : ApplicationService, ICategoryApp
    {
        private readonly IRepository<Category, string> _categoryRepository;

        public CategoryApp(IRepository<Category, string> categoryRepository)
        {
            _categoryRepository = categoryRepository;
        }

        //private readonly ICategoryRepository _categoryRepository;

        //public CategoryApp(ICategoryRepository categoryRepository)
        //{
        //    _categoryRepository = categoryRepository;
        //}

        public string GetCategoryName(string id)
        {
            //var categoryData = _categoryRepository.GetAll().FirstOrDefault(s=>s.Name == "硬件");

            var category = new Category()
            {
                Name = "硬件" + DateTime.Now.ToString("yy-MM-dd HH:mm:ss"),
                Status = 1
            };
            _categoryRepository.Insert(category);

            CurrentUnitOfWork.SaveChanges();
            return category.Name;
        }
    }
}

五、ZmBlog.Web修改

1.增加依赖

ZmBlogWebModule是web的模块,上一篇文章创建的,增加依赖ZmBlogApplicationModule

[DependsOn(typeof(AbpWebMvcModule),typeof(ZmBlogApplicationModule))]
    public class ZmBlogWebModule:AbpModule
{
    //...
}

2.修改控制器

public class HomeController : AbpController
    {
        private ICategoryApp _categoryApp;
        public HomeController(ICategoryApp categoryApp)
        {
            _categoryApp = categoryApp;
        }
        public ActionResult Index()
        {
            try
            {
                ViewBag.Name = _categoryApp.GetCategoryName("");
            }
            catch (Exception e)
            {
                ViewBag.Name = "默认分类";
                throw;
            }

            return View();
        }
//.....省略

3.页面修改

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>I Like @ViewBag.Name</h1>
</div> 

去掉没用的,直接展示效果

六、展示

运行起来的效果

数据库

由于时间原因,一些细节没有详细讲,如有不清楚请留言

时间: 2024-10-10 00:26:44

ABP架构学习系列三:手工搭建ABP框架的相关文章

ABP架构学习系列

ABP实践学习系列 ABP Zero 本地化语言的初始化和扩展 ABP Zero 导航菜单之角色权限 ABP Zero示例项目问题总结 ABP后台服务之作业调度Quartz.NET ABP架构学习系列 ABP架构学习系列一 整体项目结构及目录 ABP架构学习系列二:ABP中配置的注册和初始化 ABP架构学习系列三:手工搭建ABP框架 IOC基础学习系列 .Net IOC框架入门之一 Unity .Net IOC框架入门之二 CastleWindsor 各大主流.Net的IOC框架性能测试比较(转

angularJS学习(三)——搭建学习环境

1.安装Node.js 和Testacular 1.1. 安装Node.js及配置部分,在另一篇博文:node.js的安装里面讲到了,地址是:http://www.cnblogs.com/tianxue/p/3897103.html 1.2. 安装配置好Node.js后,安装Testacular 在控制台输入命令:npm install -g testacular 2.安装Git工具 git我已经安装了. 用以下命令从GitHub复制本教程项目的源代码文件: git clone git://gi

Android学习系列--App工程结构搭建

本文算是一篇漫谈,谈一谈关于android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构.      关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角度,看到整齐的代码,优美的分层总是一种舒服的享受的.      从艺术的角度看,其实我们是在追求一种美. 本文先分析几个当今比较流行的android软件包,最后我们汲取其中觉得优秀的部分,搭建我们自己的通用android工程模板.      1. 微盘      2. 久忆日记      3.网易新

Identity Server4学习系列三

1.简介 在Identity Server4学习系列一和Identity Server4学习系列二之令牌(Token)的概念的基础上,了解了Identity Server4的由来,以及令牌的相关知识,本文开始实战,实现Identity Server4基本的功能. 2.前提 本文基于.Net Core2.1和Indetity Server4 2.3.0,令牌处理包采用IdentityServer4.AccessTokenValidation 2.7.0 3.实战一Identity Server4服

C# Redis学习系列三:Redis配置主从

Redis配置主从 主IP :端口      192.168.0.103 6666 从IP:端口       192.168.0.108 3333 配置从库 (1)安装服务: redis-server --service-install --service-name redisService6666 --port 6666 (2)启动进程: redis-server --service-start --service-name redisService6666 (3)连接redis:redis-

web多终端开发学习系列(一)--- 响应式布局框架BootStrap学习

最近在温习web的开发,毕业之后就没接触web开发了.当时HTML5在国内貌似还是刚刚起步,能适配HTML5的浏览器很少.移动界面框架也才刚刚开始,记得当时曾经学过sencha touch的移动框架以及jquery mobile框架.这两个框架都对响应式布局进行了不错的适配及实现.响应式布局说白了就是对于多个移动终端只需一个界面即可全部适配,可大大地减少开发的工作量. 最近一年Bootstrap开始广泛地被使用了,基于此框架开发出来的插件数不胜数.所以我花了几天时间学习了下Bootstrap,本

ABP源码分析三十三:ABP.Web

ABP.Web模块并不复杂,主要完成ABP系统的初始化和一些基础功能的实现. AbpWebApplication : 继承自ASP.Net的HttpApplication类,主要完成下面三件事一,在Application_Start完成AbpBootstrapper的初始化.整个ABP系统的初始化就是通过AbpBootstrapper完成初始化的.二,在Application_BeginRequest设置根据request或cookie中的Culture信息,完成当前工作线程的CurrentCu

ABP源码分析三十一:ABP.AutoMapper

这个模块封装了Automapper,使其更易于使用. 下图描述了改模块涉及的所有类之间的关系. AutoMapAttribute,AutoMapFromAttribute和AutoMapToAttribute:这三个attribute用于标注一个类到另外一个类的map方向. AutoMapperHelper: 通过调用Automapper的API,根据类的AutoMap的特性完成类型之间的Map. AbpAutoMapperModule: 1. 查找项目中所有标注了AutoMap特性的类型,并完

ABP源码分析三十:ABP.RedisCache

ABP 通过StackExchange.Redis类库来操作Redis数据库. AbpRedisCacheModule:完成ABP.RedisCache模块的初始化(完成常规的依赖注入) AbpRedisCacheConfig:定义了connectionStringKey和databaseIdAppSetting的值.这两个值对象redis 在web.config中的key值. ABP.RedisCache模块通过读取web.config来获取redis的配置. IAbpRedisConnect