ABP應用程式層——應用服務(Application services)

來源:互聯網
上載者:User

標籤:

ABP應用程式層——應用服務(Application services)

點這裡進入ABP系列文章總目錄

 

基於DDD的現代ASP.NET開發架構--ABP系列之15、ABP應用程式層——應用服務(Application services)

 

ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱。

ABP的官方網站:http://www.aspnetboilerplate.com

ABP在Github上的開源項目:https://github.com/aspnetboilerplate

本文由東莞-天道提供翻譯

 

應用服務用於將領域(業務)邏輯暴露給展現層。展現層通過傳入DTO(資料轉送對象)參數來調用應用服務,而應用服務通過領域對象來執行相應的商務邏輯並且將DTO返回給展現層。因此,展現層和領域層將被完全隔離開來。在一個理想的層級項目中,展現層應該從不直接存取領域對象。

IApplicationService介面

在ABP中,一個應用服務需要實現IApplicationService介面。最好的實踐是針對每個應用服務都建立相應的介面。所以,我們首先定義一個應用服務介面,如下所示:

public interface IPersonAppService : IApplicationService{    void CreatePerson(CreatePersonInput input);}

IPersonAppService只有一個方法,它將被展現層調用來建立一個新的Person。CreatePersonInput是一個DTO對象,如下所示:

public class CreatePersonInput : IInputDto{    [Required]    public string Name { get; set; }    public string EmailAddress { get; set; }}

接著,我們實現IPersonAppService介面:

public class PersonAppService : IPersonAppService{    private readonly IRepository<Person> _personRepository;    public PersonAppService(IRepository<Person> personRepository)    {        _personRepository = personRepository;    }    public void CreatePerson(CreatePersonInput input)    {        var person = _personRepository.FirstOrDefault(p => p.EmailAddress == input.EmailAddress);        if (person != null)        {            throw new UserFriendlyException("There is already a person with given email address");        }        person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };        _personRepository.Insert(person);    }}

以下是幾個重要提示:

  • PersonAppService通過IRepository來執行資料庫操作。它通過構造器注入模式來產生。我們在這裡使用了依賴注入。
  • PersonAppService實現了IApplicationService(通過IPersonAppService繼承IApplicationService)。ABP會自動地把它註冊到依賴注入系統中,並可以注入到別的類型中使用。
  • CreatePerson方法需要一個CreatePersonInput類型的參數。這是一個作為輸入的DTO,它將被ABP自動驗證其資料有效性。可以查看DTO和資料有效性驗證(Validation)文檔擷取相關細節。
應用服務類型

應用服務(Application Services)需要實現IApplicationService介面。當然,你可以選擇將你的應用服務(Application Services)繼承自ApplicationService基類,這樣你的應用服務也就自然而然的實現IApplicationService介面了。ApplicationService基類提供了方便的日誌記錄和本地化功能。在此建議你針對你的應用程式建立一個應用服務基類繼承自ApplicationService類型。這樣你就可以添加一些公用的功能來提供給你的所有應用服務使用。一個應用服務樣本如下所示:

public class TaskAppService : ApplicationService, ITaskAppService{    public TaskAppService()    {        LocalizationSourceName = "SimpleTaskSystem";    }    public void CreateTask(CreateTaskInput input)    {        //記錄日誌,Logger定義在ApplicationService中        Logger.Info("Creating a new task with description: " + input.Description);        //擷取本地化文本(L是LocalizationHelper.GetString(...)的簡便版本, 定義在 ApplicationService類型)        var text = L("SampleLocalizableTextKey");        //TODO: Add new task to database...    }}

本例中我們在建構函式中定義了LocalizationSourceName,但你可以在基類中定義它,這樣你就不需要在每個具體的應用服務中定義它。查看日誌記錄(logging)和本地化(localization)文檔可以擷取更多的相關資訊。

工作單元

在ABP中,一個應用服務方法預設是一個工作單元。

(1)串連 & 交易管理 (For connection & transaction management)

在應用服務方法中,如果我們需要調用兩個倉儲方法,那麼這些方法必須為一個事務。舉個例子:

public void CreatePerson(CreatePersonInput input){    var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };        _personRepository.Insert(person);    _statisticsRepository.IncrementPeopleCount();}

我們向Person表插入一個資料,接著在其他表中修改了Person計數欄位的值。這兩個操作實現於不同的倉儲中,但是它們使用了相同的資料連線和事務。這是怎麼實現的呢?

對於UOW模式,當事務啟動並且開始執行CreatePerson方法的時候,ABP會自動地開啟資料庫。在方法結束時,如果未發生異常該事務將會被提交,並確保關閉資料庫連接。因此,CreatePerson方法中的所有資料庫操作將作為一個事務(具有原子性),當有異常拋出時這些事務中的操作將會復原。所以,樣本中的兩個倉儲方法使用了相同的資料連線和事務。

當你調用倉儲中的GetAll()方法時,它將返回一個IQueryable。資料庫連接應會在調用倉儲方法後開啟。這是因為IQueryable和LINQ的順延強制。當你調用類似ToList()方法時,資料庫查詢才會真正的開始執行。來看下面的樣本:

public SearchPeopleOutput SearchPeople(SearchPeopleInput input){    //擷取 IQueryable<Person>    var query = _personRepository.GetAll();    //過濾資料    if (!string.IsNullOrEmpty(input.SearchedName))    {        query = query.Where(person => person.Name.StartsWith(input.SearchedName));    }    if (input.IsActive.HasValue)    {        query = query.Where(person => person.IsActive == input.IsActive.Value);    }    //擷取分頁    var people = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();    return new SearchPeopleOutput {People = Mapper.Map<List<PersonDto>>(people)};}

由於一個應用服務(Application Services)方法就是一個工作單元,所以資料庫連接在方法執行期間都是開啟的。如果你在非應用服務(Application Services)中調用GetAll(),你需要顯式的使用工作單元模式。如:在Controller的Action方法中要使用GetAll()或調用多個有對資料庫操作的AppService方法時, 應該將Action方法使用virtual修飾,並在Action的上面通過[UnitOfWork]進行顯示開啟工作單元模式。

注意我使用了AutoMapper庫將List轉換成List。可以查看DTO文檔擷取相關細節。

譯者-天道註:這裡要說一下,就是uow和非uow模式的區別,兩種模式對於資料庫連接的開啟和關閉是不同的。對於控制器的方法,ABP預設是非 uow模式,此時如果調用方法會報錯,提示資料庫未串連。解決的辦法是在方法加上virtual。

(2)自動儲存資料修改 (For automatically saving changes)

對於工作單元方法(應用服務(Application Services)方法),在方法結束時ABP將會自動儲存所有資料修改。假設我們需要一個應用服務(Application Services)方法來更新一個Person的Name:

public void UpdateName(UpdateNameInput input){    var person = _personRepository.Get(input.PersonId);    person.Name = input.NewName;}

就是這樣,Name被成功修改!我們甚至不需要調用_personRepository.Update方法。ORM架構在工作單元中會跟蹤所有實體修改並將修改更新到資料庫中。

應用服務的生命週期

所有應用服務(Application Services)執行個體的生命週期都是暫時的(Transient)。這意味著在每次使用都會建立新的應用服務(Application Services)執行個體。ABP堅決地使用依賴注入技術。當一個應用服務(Application Services)類型需要被注入時,該應用服務(Application Services)類型的新執行個體將會被依賴注入容器自動建立。查看依賴注入(Dependency Injection)文檔擷取更多資訊。

 

ABP應用程式層——應用服務(Application services)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.