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

简介:   由于公司的项目才接触到ABP这个框架,当时就觉得高大上,什么IOC、AOP、ddd各种专业词汇让人激情 澎湃,但在使用过程中碰到了许多坑,可能也许是没有去看源码导致的,但工作确实没有那么多时间让人去慢慢研究。

  由于公司的项目才接触到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。
  引入相关nuget包,所有项目引用abp,ZmBlog.Infrastructure引用 Abp.EntityFramework,web项目引用后两个
Install-Package Abp -Version 0.8.4
Install-Package Abp.EntityFramework -Version 0.8.4
Install-Package Abp.Web.Mvc -Version 0.8.4
Install-Package Abp.Web.Api -Version 0.8.4
  

二、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> 

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

 六、展示

运行起来的效果

数据库

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

 

 源码下载:https://github.com/jackchn/cnblogs-xcsn-source下的ZmBlogStudy.rar

 

相关文章
|
5月前
|
人工智能 自然语言处理 数据可视化
两大 智能体框架 Dify vs Langchain 的全面分析,该怎么选?资深架构师 做一个彻底的解密
两大 智能体框架 Dify vs Langchain 的全面分析,该怎么选?资深架构师 做一个彻底的解密
两大 智能体框架 Dify vs Langchain 的全面分析,该怎么选?资深架构师 做一个彻底的解密
|
1月前
|
人工智能 自然语言处理 JavaScript
Github又一AI黑科技项目,打造全栈架构,只需一个统一框架?
Motia 是一款现代化后端框架,融合 API 接口、后台任务、事件系统与 AI Agent,支持 JavaScript、TypeScript、Python 多语言协同开发。它提供可视化 Workbench、自动观测追踪、零配置部署等功能,帮助开发者高效构建事件驱动的工作流,显著降低部署与运维成本,提升 AI 项目落地效率。
220 0
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
3 秒音频也能克隆?拆解 Spark-TTS 架构的极致小样本学习
本文深入解析了 Spark-TTS 模型的架构与原理,该模型仅需 3 秒语音样本即可实现高质量的零样本语音克隆。其核心创新在于 BiCodec 单流语音编码架构,将语音信号分解为语义 Token 和全局 Token,实现内容与音色解耦。结合大型语言模型(如 Qwen 2.5),Spark-TTS 能直接生成语义 Token 并还原波形,简化推理流程。实验表明,它不仅能克隆音色、语速和语调,还支持跨语言朗读及情感调整。尽管面临相似度提升、样本鲁棒性等挑战,但其技术突破为定制化 AI 声音提供了全新可能。
377 35
|
8月前
|
机器学习/深度学习 安全 算法
十大主流联邦学习框架:技术特性、架构分析与对比研究
联邦学习(FL)是保障数据隐私的分布式模型训练关键技术。业界开发了多种开源和商业框架,如TensorFlow Federated、PySyft、NVFlare、FATE、Flower等,支持模型训练、数据安全、通信协议等功能。这些框架在灵活性、易用性、安全性和扩展性方面各有特色,适用于不同应用场景。选择合适的框架需综合考虑开源与商业、数据分区支持、安全性、易用性和技术生态集成等因素。联邦学习已在医疗、金融等领域广泛应用,选择适配具体需求的框架对实现最优模型性能至关重要。
1593 79
十大主流联邦学习框架:技术特性、架构分析与对比研究
|
4月前
|
Java 开发者 Spring
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
203 9
|
10月前
|
存储 分布式计算 关系型数据库
架构/技术框架调研
本文介绍了微服务间事务处理、调用、大数据处理、分库分表、大文本存储及数据缓存的最优解决方案。重点讨论了Seata、Dubbo、Hadoop生态系统、MyCat、ShardingSphere、对象存储服务和Redis等技术,提供了详细的原理、应用场景和优缺点分析。
|
11月前
|
人工智能 前端开发 JavaScript
前端架构思考 :专注于多框架的并存可能并不是唯一的方向 — 探讨大模型时代前端的分层式微前端架构
随着前端技术的发展,微前端架构成为应对复杂大型应用的流行方案,允许多个团队使用不同技术栈并将其模块化集成。然而,这种设计在高交互性需求的应用中存在局限,如音视频处理、AI集成等。本文探讨了传统微前端架构的不足,并提出了一种新的分层式微前端架构,通过展示层与业务层的分离及基于功能的横向拆分,以更好地适应现代前端需求。
296 0
|
11月前
|
存储 分布式计算 API
大数据-107 Flink 基本概述 适用场景 框架特点 核心组成 生态发展 处理模型 组件架构
大数据-107 Flink 基本概述 适用场景 框架特点 核心组成 生态发展 处理模型 组件架构
432 0
|
5月前
|
Java 数据库连接 应用服务中间件
JavaWeb CRUD 与分页系统架构学习教程
本教程详细讲解了如何使用 Java Web 技术构建一个带有 CRUD 和分页功能的应用程序。以产品信息管理为例,采用 MVC 架构设计,涵盖 Servlet、JSP、JDBC/MyBatis 等技术。内容包括基础知识介绍、项目结构划分、数据库连接配置、DAO 层实现、Service 层设计、Servlet 控制层编写、JSP 前端展示以及分页功能的实现。同时涉及日志配置和 Tomcat 部署运行。通过分层开发,确保代码清晰、职责分明,便于维护和扩展。适合初学者掌握 Java Web 开发全流程,并为学习更高级框架奠定基础。
130 0
|
6月前
|
Java 数据库连接 应用服务中间件
JavaWeb CRUD 与分页系统架构学习教程
本教程将带你一步步构建一个 Java Web 的 CRUD(创建、读取、更新、删除)及分页功能的示例应用,涵盖从基本概念到完整项目架构的各个层次。
124 3

热门文章

最新文章