ABP는 모범 사례와 가장 널리 사용되는 도구를 사용하는 새로운 최신 웹 애플리케이션의 출발점입니다. 범용 애플리케이션을 위한 기본 프레임워크 또는 프로젝트 템플릿으로 사용할 수 있습니다. 다음으로 이번 글을 통해 ABP 입문 튜토리얼에 대해 자세히 소개해드리겠습니다. 관심 있는 친구들은 함께 살펴보시길 바랍니다
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, 데이터베이스 마이그레이션 및 로깅과 같은 도구를 사용할 수도 있습니다.
기업용 애플리케이션을 처음부터 만드는 것은 많은 일반적인 기본 작업을 반복해야 하기 때문에 지루한 작업입니다. 많은 회사들이 다양한 프로젝트에서 재사용할 자체 애플리케이션 프레임워크를 개발하고 있으며, 그런 다음 프레임워크를 기반으로 몇 가지 새로운 기능을 개발하고 있습니다. 하지만 모든 회사가 그런 강점을 갖고 있는 것은 아니다. 더 많이 공유할 수 있다면 모든 회사나 모든 프로젝트에 대해 유사한 코드를 반복적으로 작성하지 않아도 될 것입니다. 저자가 프로젝트 이름을 "ASP.NET Boilerplate"로 명명한 이유는 이것이 일반 기업용 WEB 애플리케이션 개발의 새로운 출발점이 되고 ABP를 프로젝트 템플릿으로 직접 사용할 수 있기를 바라는 마음에서이다.
ABP란 무엇인가요?
ABP는 모범 사례와 가장 널리 사용되는 도구를 사용하는 새로운 최신 웹 애플리케이션의 출발점입니다. 범용 애플리케이션을 위한 기본 프레임워크 또는 프로젝트 템플릿으로 사용할 수 있습니다. 기능은 다음과 같습니다:
서버 측:
최신 .NET 기술 기반(현재 ASP.NET MVC 5, Web API 2, C# 5.0은 ASP.NET 5가 공식 출시된 후 업그레이드 예정)
도메인 중심 설계 구현(엔티티, 웨어하우징, 도메인 서비스, 도메인 이벤트, 애플리케이션 서비스, 데이터 전송 개체, 작업 단위 등)
계층형 아키텍처 구현(도메인 계층, 애플리케이션 계층, 프레젠테이션 계층 및 기초 시설 계층)은 가장 널리 사용되는 오픈 소스 프레임워크/라이브러리 중 일부(아마도 사용 중인 일부일 수 있음)와 통합된 재사용 가능하고 구성 가능한 모듈을 개발하기 위한 인프라를 제공합니다.
종속성 주입을 쉽게 사용할 수 있는 인프라 제공(Castle Windsor를 종속성 주입용 컨테이너로 사용)
다양한 ORM을 지원하는 저장소 웨어하우징 모드 제공(Entity Framework, NHibernate, MangoDb 및 메모리는 데이터베이스 구현)
데이터베이스 마이그레이션(EF의 코드 우선) 모듈식 개발 지원 및 구현(각 모듈에는 독립적인 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)을 위한 프로젝트 템플릿을 제공합니다.
Web Api를 사용하여 일부 Javascript 기능을 더 쉽게 캡슐화하고 Ajax, 메시지 상자, 알림 구성 요소, 사용 중 상태 마스크 레이어 등을 더 쉽게 사용할 수 있도록 Javascript 프록시 레이어를 자동으로 생성합니다.
ABP 프레임워크 프로젝트 제외 또한 다음 기능을 구현하기 위해 "Zero"라는 모듈도 개발되었습니다.
인증 및 권한 관리(ASP.NET ID를 통해 구현)
사용자 및 역할 관리 시스템 설정 접근 관리(시스템 레벨, 테넌트 레벨, 사용자 레벨, 범위 자동 관리)
감사 로그(각 인터페이스의 호출자와 매개변수를 자동으로 기록)
ABP는 무엇인가요?
ABP는 모범 사례를 위한 애플리케이션 개발 모델을 제공합니다. 여기에는 유지 관리 가능한 대규모 애플리케이션을 쉽게 구축할 수 있는 기본 클래스, 인터페이스 및 도구가 있습니다.
그러나:
RAD 도구 중 하나가 아니며, RAD 도구의 목적은 코딩 없이 애플리케이션을 만드는 것입니다. 대신 ABP는 코딩 모범 사례를 제공합니다.
코드 생성 도구가 아닙니다. 런타임에 동적 코드를 작성하는 기능이 있지만 코드를 생성할 수는 없습니다.
올인원 프레임워크는 아닙니다. 대신 특정 작업에 널리 사용되는 도구/라이브러리(예: ORM용 EF, 로깅용 Log4Net, 종속성 주입 컨테이너인 Castle Windsor, SPA 프레임워크용 AngularJs)를 사용합니다.
몇 달 동안 ABP를 사용한 경험에 따르면 ABP는 RAD는 아니지만 프로젝트 개발에 ABP를 사용하는 것이 확실히 기존 3계층 아키텍처보다 훨씬 빠릅니다.
ABP는 코드 생성 도구는 아니지만 그로 인해 우리 프로젝트의 코드가 더 간결하고 표준화되어 코드 생성 도구를 사용하는 데 도움이 됩니다.
VS2013의 Scaffolder+T4에서 개발한 코드 생성기를 사용합니다. 이 코드 생성기는 도메인 개체의 UML 클래스 다이어그램을 기반으로 모든 프런트엔드 및 백엔드 코드와 데이터베이스를 자동으로 생성할 수 있으며 Simple CURD 모듈은 코딩이 거의 필요하지 않습니다. 주로 복잡한 비즈니스 로직으로 도메인 레이어 코드만 추가하면 됩니다. 이러한 방식으로 도메인 모델 설계에 더 많은 시간을 할애하고 코드 작성 시간을 줄일 수 있습니다.
다음은 원저자의 "간단한 작업 시스템" 예제를 사용하여 ABP를 사용하여 프로젝트를 개발하는 방법을 보여줍니다.
템플릿에서 빈 웹 애플리케이션 만들기
ABP는 새 프로젝트에 대한 시작 템플릿을 제공합니다(단, 프로젝트를 수동으로 생성하고 nuget에서 ABP 패키지를 가져올 수 있으며 템플릿 방식이 더 쉽습니다.
www.aspnetboilerplate.com/Templates로 이동하여 템플릿으로 애플리케이션을 만드세요.
SPA(AngularJs 또는 DurandalJs)를 선택하거나 MPA(클래식 다중 페이지 애플리케이션) 프로젝트를 선택할 수 있습니다. ORM 프레임워크로 Entity Framework 또는 NHibernate를 선택할 수 있습니다.
여기에서는 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의 코드 첫 번째 데이터 마이그레이션을 사용하면 SQL Server 데이터베이스에 SimpleTaskSystemDb라는 데이터베이스가 자동으로 생성됩니다.)
이제 프로젝트를 실행할 준비가 되었습니다! VS2013을 열고 F5를 누릅니다.
다음은 이 간단한 작업 시스템 프로그램을 단계별로 구현합니다.
엔티티 만들기
엔티티는 도메인의 일부이므로 Core 프로젝트에 엔터티 클래스를 작성합니다. 층.
간단한 적용 시나리오: 몇 가지 작업을 생성하고 사람들에게 할당합니다. Task와 Person이라는 두 개의 엔터티가 필요합니다.
Task 엔터티에는 설명, 생성 시간, 작업 상태 및 Person을 참조하는 선택적 탐색 속성(AssignedPerson) 등 여러 속성이 있습니다.
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 프레임워크에는 Id 속성이 있는 Entity 기본 클래스가 있습니다. Task 클래스는 Entity
Create DbContext
EntityFramework를 사용하려면 먼저 DbContext 클래스를 정의해야 합니다. ABP 템플릿은 이미 DbContext 파일을 생성했기 때문에 IDbSet에 Task 및 Person 클래스만 추가하면 됩니다. 코드:
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 입문 튜토리얼에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!