搜尋
首頁後端開發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
c#.net適合您嗎?評估其適用性c#.net適合您嗎?評估其適用性Apr 13, 2025 am 12:03 AM

c#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

.NET中的C#代碼:探索編程過程.NET中的C#代碼:探索編程過程Apr 12, 2025 am 12:02 AM

C#在.NET中的編程過程包括以下步驟:1)編寫C#代碼,2)編譯為中間語言(IL),3)由.NET運行時(CLR)執行。 C#在.NET中的優勢在於其現代化語法、強大的類型系統和與.NET框架的緊密集成,適用於從桌面應用到Web服務的各種開發場景。

C#.NET:探索核心概念和編程基礎知識C#.NET:探索核心概念和編程基礎知識Apr 10, 2025 am 09:32 AM

C#是一種現代、面向對象的編程語言,由微軟開發並作為.NET框架的一部分。 1.C#支持面向對象編程(OOP),包括封裝、繼承和多態。 2.C#中的異步編程通過async和await關鍵字實現,提高應用的響應性。 3.使用LINQ可以簡潔地處理數據集合。 4.常見錯誤包括空引用異常和索引超出範圍異常,調試技巧包括使用調試器和異常處理。 5.性能優化包括使用StringBuilder和避免不必要的裝箱和拆箱。

測試C#.NET應用程序:單元,集成和端到端測試測試C#.NET應用程序:單元,集成和端到端測試Apr 09, 2025 am 12:04 AM

C#.NET應用的測試策略包括單元測試、集成測試和端到端測試。 1.單元測試確保代碼的最小單元獨立工作,使用MSTest、NUnit或xUnit框架。 2.集成測試驗證多個單元組合的功能,常用模擬數據和外部服務。 3.端到端測試模擬用戶完整操作流程,通常使用Selenium進行自動化測試。

高級C#.NET教程:ACE您的下一次高級開發人員面試高級C#.NET教程:ACE您的下一次高級開發人員面試Apr 08, 2025 am 12:06 AM

C#高級開發者面試需要掌握異步編程、LINQ、.NET框架內部工作原理等核心知識。 1.異步編程通過async和await簡化操作,提升應用響應性。 2.LINQ以SQL風格操作數據,需注意性能。 3..NET框架的CLR管理內存,垃圾回收需謹慎使用。

C#.NET面試問題和答案:提高您的專業知識C#.NET面試問題和答案:提高您的專業知識Apr 07, 2025 am 12:01 AM

C#.NET面試問題和答案包括基礎知識、核心概念和高級用法。 1)基礎知識:C#是微軟開發的面向對象語言,主要用於.NET框架。 2)核心概念:委託和事件允許動態綁定方法,LINQ提供強大查詢功能。 3)高級用法:異步編程提高響應性,表達式樹用於動態代碼構建。

使用C#.NET建築微服務:建築師實用指南使用C#.NET建築微服務:建築師實用指南Apr 06, 2025 am 12:08 AM

C#.NET是構建微服務的熱門選擇,因為其生態系統強大且支持豐富。 1)使用ASP.NETCore創建RESTfulAPI,處理訂單創建和查詢。 2)利用gRPC實現微服務間的高效通信,定義和實現訂單服務。 3)通過Docker容器化微服務,簡化部署和管理。

C#.NET安全性最佳實踐:防止常見漏洞C#.NET安全性最佳實踐:防止常見漏洞Apr 05, 2025 am 12:01 AM

C#和.NET的安全最佳實踐包括輸入驗證、輸出編碼、異常處理、以及身份驗證和授權。 1)使用正則表達式或內置方法驗證輸入,防止惡意數據進入系統。 2)輸出編碼防止XSS攻擊,使用HttpUtility.HtmlEncode方法。 3)異常處理避免信息洩露,記錄錯誤但不返回詳細信息給用戶。 4)使用ASP.NETIdentity和Claims-based授權保護應用免受未授權訪問。

See all articles

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

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器