首頁 後端開發 C#.Net教程 ASP.NET樣板開發框架ABP系列之ABP入門教學詳解

ASP.NET樣板開發框架ABP系列之ABP入門教學詳解

Oct 14, 2017 am 10:00 AM
asp.net 框架 系列

ABP是為新的現代Web應用程式使用最佳實踐和使用最受歡迎工具的一個起點。可作為一般用途的應用程式的基礎架構或專案範本。接下來透過本文向大家詳細介紹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、資料庫遷移(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類型的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入門教學詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

小米 15 系列全代號曝光:Dada、Haotian、Xuanyuan 小米 15 系列全代號曝光:Dada、Haotian、Xuanyuan Aug 22, 2024 pm 06:47 PM

小米15系列預計10月正式發布,其全系列代號已在外媒MiCode程式碼庫曝光。其中,旗艦級小米15Ultra代號為"Xuanyuan"(意為"軒轅"),此名源自中國神話中的黃帝,象徵尊貴。小米15的代號為"Dada",而小米15Pro則以"Haotian"(意為"昊天")為名。小米15SPro內部代號為"dijun",暗指《山海經》創世神帝俊。小米15Ultra系列涵蓋

華為 Mate 60 系列最佳入手時機,新增 AI 消除 + 影像升級,更可享秋日禮遇活動 華為 Mate 60 系列最佳入手時機,新增 AI 消除 + 影像升級,更可享秋日禮遇活動 Aug 29, 2024 pm 03:33 PM

自去年华为Mate60系列开售以来,我个人就一直将Mate60Pro作为主力机使用。在将近一年的时间里,华为Mate60Pro经过多次OTA升级,综合体验有了显著提升,给人一种常用常新的感觉。比如近期,华为Mate60系列就再度迎来了影像功能的重磅升级。首先是新增AI消除功能,可以智能消除路人、杂物并对空白部分进行自动补充;其次是主摄色准、长焦清晰度均有明显升级。考虑到现在是开学季,华为Mate60系列还推出了秋日礼遇活动:购机可享至高800元优惠,入手价低至4999元。常用常新的产品力加上超值

如何評估Java框架商業支援的性價比 如何評估Java框架商業支援的性價比 Jun 05, 2024 pm 05:25 PM

評估Java框架商業支援的性價比涉及以下步驟:確定所需的保障等級和服務等級協定(SLA)保證。研究支持團隊的經驗和專業知識。考慮附加服務,如昇級、故障排除和效能最佳化。權衡商業支援成本與風險緩解和提高效率。

PHP 框架的學習曲線與其他語言框架相比如何? PHP 框架的學習曲線與其他語言框架相比如何? Jun 06, 2024 pm 12:41 PM

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

PHP 框架的輕量級選項如何影響應用程式效能? PHP 框架的輕量級選項如何影響應用程式效能? Jun 06, 2024 am 10:53 AM

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

golang框架文件最佳實踐 golang框架文件最佳實踐 Jun 04, 2024 pm 05:00 PM

編寫清晰全面的文件對於Golang框架至關重要。最佳實踐包括:遵循既定文件風格,例如Google的Go程式設計風格指南。使用清晰的組織結構,包括標題、子標題和列表,並提供導覽。提供全面且準確的信息,包括入門指南、API參考和概念。使用程式碼範例說明概念和使用方法。保持文件更新,追蹤變更並記錄新功能。提供支援和社群資源,例如GitHub問題和論壇。建立實際案例,如API文件。

如何為不同的應用場景選擇最佳的golang框架 如何為不同的應用場景選擇最佳的golang框架 Jun 05, 2024 pm 04:05 PM

根據應用場景選擇最佳Go框架:考慮應用類型、語言特性、效能需求、生態系統。常見Go框架:Gin(Web應用)、Echo(Web服務)、Fiber(高吞吐量)、gorm(ORM)、fasthttp(速度)。實戰案例:建構RESTAPI(Fiber),與資料庫互動(gorm)。選擇框架:效能關鍵選fasthttp,靈活Web應用選Gin/Echo,資料庫互動選gorm。

golang框架開發實戰詳解:問題答疑 golang框架開發實戰詳解:問題答疑 Jun 06, 2024 am 10:57 AM

在Go框架開發中,常見的挑戰及其解決方案是:錯誤處理:利用errors套件進行管理,並使用中間件集中處理錯誤。身份驗證和授權:整合第三方庫並建立自訂中間件來檢查憑證。並發處理:利用goroutine、互斥鎖和通道來控制資源存取。單元測試:使用gotest包,模擬和存根隔離,並使用程式碼覆蓋率工具確保充分性。部署和監控:使用Docker容器打包部署,設定資料備份,透過日誌記錄和監控工具追蹤效能和錯誤。

See all articles