ABP是“ASP.NET Boilerplate Project (ASP.NET榜样项目)”的简称。
ASP.NET Boilerplate是一个用最好实践和盛行手艺开辟当代WEB运用顺序的新出发点,它旨在成为一个通用的WEB运用顺序框架和项目模板。
ABP的官方网站:http://www.aspnetboilerplate.com
ABP在Github上的开源项目:https://github.com/aspnetboilerplate
ABP 的由来
“DRY——防止反复代码”是一个优异的开辟者在开辟软件时所具有的最重要的头脑之一。我们在开辟企业WEB运用顺序时都有一些相似的需求,比方:都须要登录页面、用户/角色治理、权限考证、数据有效性考证、多语言/当地化等等。一个高品质的大型软件都邑运用一些最好实践,比方分层体系组织、范畴驱动设想、依靠注入等。我们也可能会采纳ORM、数据库迁徙(Database Migrations)、日记纪录(Logging)等东西。
从零开始竖立一个企业运用顺序是一件烦琐的事,由于须要反复做很多罕见的基本事情。很多公司都在开辟本身的运用顺序框架来重用于差别的项目,然后在框架的基本上开辟一些新的功用。但并非每一个公司都有如许的气力。假如我们能够分享的更多,或许能够防止每一个公司或每一个项目标反复编写相似的代码。作者之所以把项目命名为“ASP.NET Boilerplate”,就是愿望它能成为开辟平常企业WEB运用的新出发点,直接把ABP作为项目模板。
ABP是什么?
ABP是为新的当代Web运用顺序运用最好实践和运用最盛行东西的一个出发点。可作为平经常使用处的运用顺序的基本框架或项目模板。它的功用包含:
效劳器端:
基于最新的.NET手艺 (如今是ASP.NET MVC 5、Web API 2、C# 5.0,在ASP.NET 5正式宣布后会升级)
完成范畴驱动设想(实体、仓储、范畴效劳、范畴事宜、运用效劳、数据传输对象,事情单位等等)
完成分层体系组织(范畴层,运用层,展示层和基本设施层)供应了一个基本架构来开辟可重用可设置的模块集成一些最盛行的开源框架/库,或许有些是你正在运用的。
供应了一个基本架构让我们很方便地运用依靠注入(运用Castle Windsor作为依靠注入的容器)
供应Repository仓储形式支撑差别的ORM(已完成Entity Framework 、NHibernate、MangoDb和内存数据库)
支撑并完成数据库迁徙(EF 的 Code first)模块化开辟(每一个模块有自力的EF DbContext,可零丁指定数据库)
包含一个简朴的和天真的多语言/当地化体系
包含一个 EventBus来完成效劳器端全局的范畴事宜一致的异常处置惩罚(运用层险些不须要处置惩罚本身写异常处置惩罚代码)
数据有效性考证(Asp.NET MVC只能做到Action要领的参数考证,ABP完成了Application层要领的参数有效性考证)
经由过程Application Services自动竖立Web Api层(不须要写ApiController层了)
供应基类和协助类让我们方便地完成一些罕见的使命
运用“商定优于设置准绳”
客户端:
Bootstrap、Less、AngularJs、jQuery、Modernizr和其他JS库: jQuery.validate、jQuery.form、jQuery.blockUI、json2等
为单页面运用顺序(AngularJs、Durandaljs)和多页面运用顺序(Bootstrap+Jquery)供应了项目模板。
自动竖立Javascript 的代办层来更方便运用Web Api封装一些Javascript 函数,更方便地运用ajax、音讯框、关照组件、忙状况的遮罩层等等
除ABP框架项目之外,还开辟了名叫“Zero”的模块,完成了以下功用:
身份考证与受权治理(经由过程ASP.NET Identity完成的)
用户&角色治理体系设置存取治理(体系级、租户级、用户级,作用局限自动治理)
审计日记(自动纪录每一次接口的挪用者和参数)
ABP不是什么?
ABP供应了一个运用顺序开辟模子用于最好实践。它具有基本类、接口和东西使我们轻易竖立起可保护的大规模的运用顺序。
然则:
它不是RAD东西之一,RAD东西的目标是无需编码竖立运用顺序。相反,ABP供应了一种编码的最好实践。
它不是一个代码生成东西。在运转时虽然它有一些特征构建动态代码,但它不能生成代码。
它不是一个一体化的框架。相反,它运用盛行的东西/库来完成特定的使命(比方用EF做ORM,用Log4Net做日记纪录,使得Castle Windsor作为赖注入容器, AngularJs 用于SPA 框架)。
就我运用了ABP几个月的履历来看,虽然ABP不是RAD,然则用它开辟项目绝对照传统三层架构要快很多。
虽然ABP不是代码生成东西,但由于有了它,使我们项目标代码更简约范例,这有利于运用代码生成东西。
我本身运用VS2013的Scaffolder+T4开辟的代码生成器,可根据范畴对象的UML类图自动生成悉数前后端代码和数据库,简朴的CURD模块险些不须要编写代码,有庞杂营业逻辑的模块重要补充范畴层代码即可。如许就可以把时候多花在范畴模子的设想上,削减写代码的时候。
下面经由过程原作者的“简朴使命体系”例子,演示怎样运用ABP开辟项目
从模板竖立空的web运用顺序
ABP供应了一个启动模板用于新建的项目(只管你妙手动地竖立项目而且从nuget取得ABP包,模板的体式格局更轻易)。
转到www.aspnetboilerplate.com/Templates从模板竖立你的运用顺序。
你能够挑选SPA(AngularJs或DurandalJs)或许挑选MPA(典范的多页面运用顺序)项目。能够挑选Entity Framework或NHibernate作为ORM框架。
这里我们挑选AngularJs和Entity Framework,填入项目名称“SimpleTaskSystem”,点击“CREATE MY PROJECT”按钮能够下载一个zip压缩包,解压后获得VS2013的解决方案,运用的.NET版本是 4.5.1。
每一个项目里援用了Abp组件和其他第三方组件,须要从Nuget下载。
黄色感叹号图标,示意这个组件在当地文件夹中不存在,须要从Nuget上复原。操纵以下:
要让项目运转起来,还得竖立一个数据库。这个模板假定你正在运用SQL2008或许更新的版本。固然也能够很方便地换成其他的关联型数据库。
翻开Web.Config文件能够检察和设置链接字符串:
<add name="Default" connectionString="Server=localhost; Database=SimpleTaskSystemDb; Trusted_Connection=True;" />
(在背面用到EF的Code first数据迁徙时,会自动在SQL Server数据库中竖立一个名为SimpleTaskSystemDb的数据库。)
就如许,项目已预备好运转了!翻开VS2013而且按F5:
下面将逐渐完成这个简朴的使命体系顺序
竖立实体
把实体类写在Core项目中,由于实体是范畴层的一部分。
一个简朴的运用场景:竖立一些使命(tasks)并分派给人。 我们须要Task和Person这两个实体。
Task实体有几个属性:形貌(Description)、竖立时候(CreationTime)、使命状况(State),另有可选的导航属性(AssignedPerson)来援用Person。
public class Task : Entity<long> { [ForeignKey("AssignedPersonId")] public virtual Person AssignedPerson { get; set; } public virtual int? AssignedPersonId { get; set; } public virtual string Description { get; set; } public virtual DateTime CreationTime { get; set; } public virtual TaskState State { get; set; } public Task() { CreationTime = DateTime.Now; State = TaskState.Active; } }
Person实体更简朴,只定义了一个Name属性:
public class Person : Entity { public virtual string Name { get; set; } }
在ABP框架中,有一个Entity基类,它有一个Id属性。由于Task类继承自Entity<long>,所以它有一个long范例的Id。Person类有一个int范例的Id,由于int范例是Entity基类Id的默许范例,没有迥殊指定范例时,实体的Id就是int范例。
竖立DbContext
运用EntityFramework须要先定义DbContext类,ABP的模板已竖立了DbContext文件,我们只须要把Task和Person类增加到IDbSet,请看代码:
public class SimpleTaskSystemDbContext : AbpDbContext { public virtual IDbSet<Task> Tasks { get; set; } public virtual IDbSet<Person> People { get; set; } public SimpleTaskSystemDbContext() : base("Default") { } public SimpleTaskSystemDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } }
经由过程Database Migrations竖立数据库表
我们运用EntityFramework的Code First形式竖立数据库架构。ABP模板生成的项目已默许开启了数据迁徙功用,我们修正SimpleTaskSystem.EntityFramework项面前目今Migrations文件夹下的Configuration.cs文件:
internal sealed class Configuration : DbMigrationsConfiguration<SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext> { public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext context) { context.People.AddOrUpdate( p => p.Name, new Person {Name = "Isaac Asimov"}, new Person {Name = "Thomas More"}, new Person {Name = "George Orwell"}, new Person {Name = "Douglas Adams"} ); } }
在VS2013底部的“顺序包治理器控制台”窗口中,挑选默许项目并实行命令“Add-Migration InitialCreate”
会在Migrations文件夹下生成一个xxxx-InitialCreate.cs文件,内容以下:
public partial class InitialCreate : DbMigration { public override void Up() { CreateTable( "dbo.StsPeople", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), }) .PrimaryKey(t => t.Id); CreateTable( "dbo.StsTasks", c => new { Id = c.Long(nullable: false, identity: true), AssignedPersonId = c.Int(), Description = c.String(), CreationTime = c.DateTime(nullable: false), State = c.Byte(nullable: false), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.StsPeople", t => t.AssignedPersonId) .Index(t => t.AssignedPersonId); } public override void Down() { DropForeignKey("dbo.StsTasks", "AssignedPersonId", "dbo.StsPeople"); DropIndex("dbo.StsTasks", new[] { "AssignedPersonId" }); DropTable("dbo.StsTasks"); DropTable("dbo.StsPeople"); } }
然后继承在“顺序包治理器控制台”实行“Update-Database”,会自动在数据库竖立响应的数据表:
PM> Update-Database
数据库显现以下:
(今后修正了实体,能够再次实行Add-Migration和Update-Database,就可以很轻松的让数据库组织与实体类的同步)
定义仓储接口
经由过程仓储形式,能够更好把营业代码与数据库操纵代码更好的星散,能够针对差别的数据库有差别的完成类,而营业代码不须要修正。
定义仓储接口的代码写到Core项目中,由于仓储接口是范畴层的一部分。
我们先定义Task的仓储接口:
public interface ITaskRepository : IRepository<Task, long> {
它继承自ABP框架中的IRepository泛型接口。
在IRepository中已定义了经常使用的增编削查要领:
所以ITaskRepository默许就有了上面那些要领。能够再加上它独占的要领GetAllWithPeople(...)。
不须要为Person类竖立一个仓储类,由于默许的要领已够用了。ABP供应了一种注入通用仓储的体式格局,将在背面“竖立运用效劳”一节的TaskAppService类中看到。
完成仓储类
我们将在EntityFramework项目中完成上面定义的ITaskRepository仓储接口。
经由过程模板竖立的项目已定义了一个仓储基类:SimpleTaskSystemRepositoryBase(这是一种比较好的实践,由于今后能够在这个基类中增加通用的要领)。
public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository { public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state) { //在仓储要领中,不必处置惩罚数据库衔接、DbContext和数据事件,ABP框架会自动处置惩罚。 var query = GetAll(); //GetAll() 返回一个 IQueryable<T>接口范例 //增加一些Where前提 if (assignedPersonId.HasValue) { query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value); } if (state.HasValue) { query = query.Where(task => task.State == state); } return query .OrderByDescending(task => task.CreationTime) .Include(task => task.AssignedPerson) .ToList(); } }
TaskRepository继承自SimpleTaskSystemRepositoryBase而且完成了上面定义的ITaskRepository接口。
竖立运用效劳(Application Services)
在Application项目中定义运用效劳。起首定义Task的运用效劳层的接口:
public interface ITaskAppService : IApplicationService { GetTasksOutput GetTasks(GetTasksInput input); void UpdateTask(UpdateTaskInput input); void CreateTask(CreateTaskInput input); }
ITaskAppService继承自IApplicationService,ABP自动为这个类供应一些功用特征(比方依靠注入和参数有效性考证)。
然后,我们写TaskAppService类来完成ITaskAppService接口:
public class TaskAppService : ApplicationService, ITaskAppService { private readonly ITaskRepository _taskRepository; private readonly IRepository<Person> _personRepository; /// <summary> /// 组织函数自动注入我们所须要的类或接口 /// </summary> public TaskAppService(ITaskRepository taskRepository, IRepository<Person> personRepository) { _taskRepository = taskRepository; _personRepository = personRepository; } public GetTasksOutput GetTasks(GetTasksInput input) { //挪用Task仓储的特定要领GetAllWithPeople var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State); //用AutoMapper自动将List<Task>转换成List<TaskDto> return new GetTasksOutput { Tasks = Mapper.Map<List<TaskDto>>(tasks) }; } public void UpdateTask(UpdateTaskInput input) { //能够直接Logger,它在ApplicationService基类中定义的 Logger.Info("Updating a task for input: " + input); //经由过程仓储基类的通用要领Get,猎取指定Id的Task实体对象 var task = _taskRepository.Get(input.TaskId); //修正task实体的属性值 if (input.State.HasValue) { task.State = input.State.Value; } if (input.AssignedPersonId.HasValue) { task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value); } //我们都不须要挪用Update要领 //由于运用效劳层的要领默许开启了事情单位形式(Unit of Work) //ABP框架会事情单位完成时自动保留对实体的一切变动,除非有异常抛出。有异常时会自动回滚,由于事情单位默许开启数据库事件。 } public void CreateTask(CreateTaskInput input) { Logger.Info("Creating a task for input: " + input); //经由过程输入参数,竖立一个新的Task实体 var task = new Task { Description = input.Description }; if (input.AssignedPersonId.HasValue) { task.AssignedPersonId = input.AssignedPersonId.Value; } //挪用仓储基类的Insert要领把实体保留到数据库中 _taskRepository.Insert(task); } }
TaskAppService运用仓储举行数据库操纵,它通往组织函数注入仓储对象的援用。
数据考证
假如运用效劳(Application Service)要领的参数对象完成了IInputDto或IValidate接口,ABP会自动举行参数有效性考证。
CreateTask要领有一个CreateTaskInput参数,定义以下:
public class CreateTaskInput : IInputDto { public int? AssignedPersonId { get; set; } [Required] public string Description { get; set; } }
Description属性经由过程注解指定它是必填项。也能够运用其他 Data Annotation 特征。
假如你想运用自定义考证,你能够完成ICustomValidate 接口:
public class UpdateTaskInput : IInputDto, ICustomValidate { [Range(1, long.MaxValue)] public long TaskId { get; set; } public int? AssignedPersonId { get; set; } public TaskState? State { get; set; } public void AddValidationErrors(List<ValidationResult> results) { if (AssignedPersonId == null && State == null) { results.Add(new ValidationResult("AssignedPersonId和State不能同时为空!", new[] { "AssignedPersonId", "State" })); } } }
你能够在AddValidationErrors要领中写自定义考证的代码。
竖立Web Api效劳
ABP能够异常轻松地把Application Service的public要领宣布成Web Api接口,能够供客户端经由过程ajax挪用。
DynamicApiControllerBuilder .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem") .Build();
SimpleTaskSystemApplicationModule这个顺序集合一切继承了IApplicationService接口的类,都邑自动竖立响应的ApiController,个中的公然要领,就会转换成WebApi接口要领。
能够经由过程http://xxx/api/services/tasksystem/Task/GetTasks如许的路由地点举行挪用。
经由过程上面的案例,大抵引见了范畴层、基本设施层、运用效劳层的用法。
如今,能够在ASP.NET MVC的Controller的Action要领中直接挪用Application Service的要领了。
假如用SPA单页编程,能够直接在客户端经由过程ajax挪用响应的Application Service的要领了(经由过程竖立了动态Web Api)。
总结
以上就是ASP.NET榜样开辟框架ABP系列之ABP入门教程详解的细致内容,更多请关注ki4网别的相干文章!