ABP(現代ASP.NET樣板開發框架)系列之2、ABP入門教程
基於DDD的現代ASP.NET開發框架--ABP系列之2、ABP入門教程
ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程式的新起點,它旨在成為一個通用的WEB應用程式框架和專案模板。
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包,模板的方式更容易)。
你可以選擇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> { List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state); }
它繼承自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)。
由於時間關係,展現層沒有在本文中介紹,將放到以後的文章介紹。後續文章中也將會詳細介紹每一層的具體知識要點。
如果想立即看到更多展示,可以檢視我以前的文章,比較完整的演示了一個簡單模組的開發,包括前後端各層的程式碼。(我自己專案用的ABP框架是在原作者的基礎上做了一些修改,所以有些地方可能跟原作者的ABP不完全相同。)
由於演示一個完整的開發流程工作量巨大,寫文章很難說得清楚,忙過這段時間我會準備用視訊或YY線上的方式來分享,到時也可以分享我使用VS2013的Scaffolder+T4開發的程式碼生成器。
希望更多國內的架構師能關注到ABP這個專案,也許這其中有能幫助到您的地方,也許有您的參與,這個專案可以發展得更好。
歡迎加ABP架構設計交流QQ群:134710707
相關推薦
ABP(現代ASP.NET樣板開發框架)系列之2、ABP入門教程
基於DDD的現代ASP.NET開發框架--ABP系列之2、ABP入門教程 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程式的新起點,它旨在成為一個通用的
ABP(現代ASP.NET樣板開發框架)系列之10、ABP領域層——實體
基於DDD的現代ASP.NET開發框架--ABP系列之10、ABP領域層——實體 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由深圳-Carl提供翻譯 實體是DDD(領域驅動設計)的核心概念之一。Eric Eva
ABP(現代ASP.NET樣板開發框架)系列之4、ABP模組系統
基於DDD的現代ASP.NET開發框架--ABP系列之4、ABP模組系統 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由東莞-天道提供翻譯 ABP模組系統簡介 ABP框架提供了建立和組裝模組的基礎,一個模組
ABP(現代ASP.NET樣板開發框架)系列之6、ABP依賴注入
基於DDD的現代ASP.NET開發框架--ABP系列之6、ABP依賴注入 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由 上海-半冷 提供翻譯 什麼是依賴注入 如果你已經知道依賴注入的概念,建構函式和屬性注入
ABP(現代ASP.NET樣板開發框架)系列之9、ABP設定管理
基於DDD的現代ASP.NET開發框架--ABP系列之9、ABP設定管理 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由山東-李偉提供翻譯 介紹 每個應用程式需要儲存一些設定並在應用程式的某個地方使用這些設定。
ABP(現代ASP.NET樣板開發框架)系列之17、ABP應用層——引數有效性驗證
基於DDD的現代ASP.NET開發框架--ABP系列之17、ABP應用層——引數有效性驗證 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 應用程式的輸入資料首先應該被檢驗是否有效。輸入的資料能被使用者或其他應用程式提
ABP(現代ASP.NET樣板開發框架)系列之16、ABP應用層——資料傳輸物件(DTOs)
基於DDD的現代ASP.NET開發框架--ABP系列之16、ABP應用層——資料傳輸物件(DTOs) ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 資料傳輸物件(Data Transfer Objects)用於應用層
ABP(現代ASP.NET樣板開發框架)系列之13、ABP領域層——資料過濾器(Data filters)
基於DDD的現代ASP.NET開發框架--ABP系列之13、ABP領域層——資料過濾器(Data filters) ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 介紹 在資料庫開發中,我們一般會運用軟刪除(soft
ABP(現代ASP.NET樣板開發框架)系列之21、ABP展現層——Javascript函式庫
基於DDD的現代ASP.NET開發框架--ABP系列之21、ABP展現層——Javascript函式庫 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 ASP.NET Boilerplate的js庫提供了一些讓java
ABP(現代ASP.NET樣板開發框架)系列之14、ABP領域層——領域事件(Domain events)
基於DDD的現代ASP.NET開發框架--ABP系列之14、ABP領域層——領域事件(Domain events) ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 在C#中,一個類可以定義其專屬的事件並且其它類可以註冊該事
ABP(現代ASP.NET樣板開發框架)系列之5、ABP啟動配置
基於DDD的現代ASP.NET開發框架--ABP系列之5、ABP啟動配置 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由 東莞-天道 提供翻譯 譯者注:在看這一節的內容之前,建議大家先下載module-ze
ABP(現代ASP.NET樣板開發框架)系列之3、ABP分層架構
基於DDD的現代ASP.NET開發框架--ABP系列之3、ABP分層架構 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 前言 為了減少複雜性和提高程式碼的可重用性,採用分層架構是一種被廣泛接受的技術。為了實現分層的
ABP(現代ASP.NET樣板開發框架)系列之19、ABP應用層——審計日誌
基於DDD的現代ASP.NET開發框架--ABP系列之19、ABP應用層——審計日誌 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 維基百科定義:審計跟蹤(也稱為稽核日誌)是一個安全相關的時間順序記錄,記錄這些記錄的
ABP(現代ASP.NET樣板開發框架)系列之15、ABP應用層——應用服務(Application services)
基於DDD的現代ASP.NET開發框架--ABP系列之15、ABP應用層——應用服務(Application services) ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由東莞-天道提供翻譯 應用服務用於將領
ABP(現代ASP.NET樣板開發框架)系列之23、ABP展現層——異常處理
基於DDD的現代ASP.NET開發框架--ABP系列之23、ABP展現層——異常處理 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 在 web 應用程式中,異常通常是在 MVC Controller actions
ABP(現代ASP.NET樣板開發框架)系列之8、ABP日誌管理
基於DDD的現代ASP.NET開發框架--ABP系列之8、ABP日誌管理 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 本文由東莞-天道提供翻譯 Server side(伺服器端) ASP.NET Boilerpla
ABP(現代ASP.NET樣板開發框架)系列之1、ABP總體介紹
基於DDD的現代ASP.NET開發框架--ABP系列之1、ABP總體介紹 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程式的新起點,它旨在成為一個通用的
ABP(現代ASP.NET樣板開發框架)系列之12、ABP領域層——工作單元(Unit Of work)
基於DDD的現代ASP.NET開發框架--ABP系列之12、ABP領域層——工作單元(Unit Of work) ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 通用連線和事務管理方法 連線和事務管理是使用資料庫的應用程
ABP(現代ASP.NET樣板開發框架)系列之22、ABP展現層——導航欄設定
基於DDD的現代ASP.NET開發框架--ABP系列之22、ABP展現層——導航欄設定 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 每一個WEB應用程式都有導航選單,Abp也為使用者提供了通用的建立和顯示選單方式。
ABP(現代ASP.NET樣板開發框架)系列之7、ABP Session管理
基於DDD的現代ASP.NET開發框架--ABP系列之7、ABP Session管理 ABP是“ASP.NET Boilerplate Project (ASP.NET樣板專案)”的簡稱。 簡介 如果一個應用程式需要登入,則它必須知道當前使用者執行了什麼操作。因此ASP.