由于公司的项目才接触到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.
Install-Package Abp.EntityFramework -Version 0.8.
Install-Package Abp.Web.Mvc -Version 0.8.
Install-Package Abp.Web.Api -Version 0.8.
  

二、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 =
};
_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

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

  1. ABP架构学习系列一 整体项目结构及目录

    本系列是基于aspnetboilerplate-0.8.4.0版本写的,其中原因是由于较高的版本太抽象难以理解和分析,对于还菜菜的我要花更多的时间去学习. abp的源码分析学习主要来源于 HK Zha ...

  2. ABP架构学习系列

    ABP实践学习系列 ABP Zero 本地化语言的初始化和扩展 ABP Zero 导航菜单之角色权限 ABP Zero示例项目问题总结  ABP后台服务之作业调度Quartz.NET   ABP架构学 ...

  3. ABP架构学习系列二:ABP中配置的注册和初始化

    一.手工搭建平台 1.创建项目 创建MVC5项目,手动引入Abp.Abp.Web.Abp.Web.Mvc.Abp.Web.Api 使用nuget添加Newtonsoft.Json.Castle.Cor ...

  4. ABP架构学习系列四:集成Dapper

    之前,一直想集成Dapper到项目中,但是一直没成功,今天把abp升级到最新版,然后按教程来,就可以了,呵呵    现在,基于上一篇的源码进行升级和集成dapper,将abp升级到3.8.2   官方 ...

  5. 手工搭建ABP框架(1) - Web项目

    为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7295533.html ABP是 ASP.NET Boilerplate Proj ...

  6. MyBatis学习系列三——结合Spring

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...

  7. scrapy爬虫学习系列三:scrapy部署到scrapyhub上

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

  8. RabbitMQ学习系列三-C#代码接收处理消息

    RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理 http://www.80iter.com/blog/1438251320680361 http://www. ...

  9. DocX开源WORD操作组件的学习系列三

    DocX学习系列 DocX开源WORD操作组件的学习系列一 : http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_sharp_001_docx1.htm ...

随机推荐

  1. python 正则表达式之零宽断言

    零宽断言:用于查找特定内容之前或之后的内容,但并不包括特定内容本身.对于零宽断言来说,我认为最重要的一个概念是位置,零宽断言用于指定一个位置,这个位置应该满足一定的条件(它附近满足什么表达式),并且这 ...

  2. javascript 命名空间与运用(前端基础系列)

    所谓代码,当你随便命名一个变量:var name = "ukerxi"; 就是一句代码:但当你的代码写出来后,对于后续维护及阅读的人,就可以看出代码是否,易读,易理解:优雅的代码总 ...

  3. C++ stack

    stack 栈,一种后进先出的数据结构,在c++ stl里作为容器适配器,string,vector,deque,在内存中是连续的 声明方式 stack<int,deque<T>&g ...

  4. hdu4893 Wow! Such Sequence!

    线段树结点上保存一个一般的sum值,再同一时候保存一个fbsum,表示这个结点表示的一段数字若为斐波那契数时的和 当进行3操作时,仅仅用将sum = fbsum就可以 其它操作照常进行,仅仅是单点更新 ...

  5. 利用linux shell自己主动顶贴

    在论坛上面发帖问个什么东西的话,一旦不顶.帖子就秒沉了,可是又实在不想每时每刻都去顶,怎么办?以下展示了怎样利用shell 的crontab实现自己主动顶贴. 闲话不多说了,以豆瓣为例-– 1: 用c ...

  6. JQuery插件开发标准写法

    ;//step01 定义JQuery的作用域 (function ($) { //step03-a 插件的默认值属性 var defaults = { prevId: 'prevBtn', prevT ...

  7. angularf封装echarts

    前言:angular中快速使用echarts 在html使用ehart很简单,你只需要引入文件和按照官方例子按照对应参数配置和数据填充就Ok了,那么在angular中怎么使用eharts(可以使用ec ...

  8. Bandit Wargame Level18 Writeup(interactive shell and .bashrc )

    Bandit Level 18 → Level 19 Level Goal The password for the next level is stored in a file readme in ...

  9. gearman学习笔记1

    1.简介       gearman是一个分布式开发框架,适合处理一些必须处理但是不影响主流程的操作,比如保存日志.发送邮件.缩略图片等.最早是基于perl语言的,2008年发布的时候改为C++语言开 ...

  10. XSS注入,js脚本注入后台

    曾经一度流行sql注入,由于现在技术的更新,已经看不到这问题了,但是又出来新的安全问题,XSS攻击,他的原理就是在前端提交表单的时候,在input标签当中输入js脚本,通过js脚本注入后台,请看下图. ...