<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ## 思路 我更傾向逐個功能地推進應用開發。本節將說明如何在 UI 上顯示產品列表。 1. 首先,我們會為`Product`實體定義一個`ProductDto`; 2. 然后,我們將創建一個向表示層返回產品列表的應用服務方法; 3. 此外,我們將學習如何自動映射`Product`到`ProductDto` 在創建 UI 之前,我將向您展示如何為應用服務編寫**自動化測試**。這樣,在開始 UI 開發之前,我們就可以確定應用服務是否正常工作。 在整個在開發過程中,我們將探索 ABP 框架的一些能力,例如自動 API 控制器和動態 JavaScript 代理系統。 最后,我們將創建一個新頁面,并在其中添加一個數據表,然后從服務端獲取產品列表,并將其顯示在 UI 上。 梳理完思路,我們從創建一個`ProductDto`類開始。 ## ProductDto 類 DTO 用于在應用層和表示層之間傳輸數據。最佳實踐是將 DTO 返回到表示層而不是實體,因為將實體直接暴露給表示層可能導致序列化和安全問題,有了DTO,我們不但可以抽象實體,對接口展示內容也更加可控。 為了在 UI 層中可復用,DTO 規定在Application.Contracts項目中進行定義。我們首先在\*.Application.Contracts項目的Products文件夾中創建一個`ProductDto`類: ``` using System; using Volo.Abp.Application.Dtos; namespace ProductManagement.Products { ????public class ProductDto : AuditedEntityDto<Guid> ????{ ????????public Guid CategoryId { get; set; } ????????public string CategoryName { get; set; } ????????public string Name { get; set; } ????????public float Price { get; set; } ????????public bool IsFreeCargo { get; set; } ????????public DateTime ReleaseDate { get; set; } ????????public ProductStockState StockState { get; set; } ????} } ``` `ProductDto`與實體類基本相似,但又有以下區別: * 它派生自`AuditedEntityDto<Guid>`,它定義了`Id`、`CreationTime`、`CreatorId`、`LastModificationTime`和`LastModifierId`屬性(我們不需要做刪除審計`DeletionTime`,因為刪除的實體不是從數據庫中讀取的)。 * 我們沒有向實體`Category`添加導航屬性,而是使用了一個`string`類型的`CategoryName`的屬性,用以在 UI 上顯示。 我們將使用使用`ProductDto`類從`IProductAppService`接口返回產品列表。 ## 產品應用服務 **應用服務**實現了應用的業務邏輯,UI 調用它們用于用戶交互。通常,應用服務方法返回一個 DTO。 #### 1 應用服務與 API 控制器 >[warning] ABP的應用服務和MVC 中的 API 控制器有何區別? 您可以將應用服務與 [ASP.NET](http://ASP.NET) Core MVC 中的 API 控制器進行比較。雖然它們有相似之處,但是: 1. 應用服務更適合 DDD ,它們不依賴于特定的 UI 技術。 2. 此外,ABP 可以自動將您的應用服務公開為 HTTP API。 我們在\*.Application.Contracts項目的Products文件夾中創建一個`IProductAppService`接口: ``` using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; namespace ProductManagement.Products { ????public interface IProductAppService : IApplicationService ????{ ????????Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input); ????} } ``` 我們可以看到一些預定義的 ABP 類型: * `IProductAppService`約定從`IApplicationService`接口,這樣ABP 就可以識別應用服務。 * `GetListAsync`方法的入參`PagedAndSortedResultRequestDto`是 ABP 框架的標準 DTO 類,它定義了`MaxResultCount`、`SkipCount`和`Sorting`屬性。 * `GetListAsync`方法返回`PagedResultDto<ProductDto>`,其中包含一個`TotalCount`屬性和一個`ProductDto`對象集合,這是使用 ABP 框架返回分頁結果的便捷方式。 當然,您可以使用自己的 DTO 代替這些預定義的 DTO。但是,當您想要標準化一些常見問題,避免到處都使用相同的命名時,它們非常有用。 #### 2 異步方法 將所有應用服務方法定義為異步方法是最佳實踐。如果您定義為同步方法,在某些情況下,某些 ABP 功能(例如工作單元)可能無法按預期工作。 現在,我們可以實現`IProductAppService`接口來執行用例。 #### 3 產品應用服務 我們在ProductManagement.Application項目中創建一個`ProductAppService`類: ``` using System.Linq.Dynamic.Core; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; namespace ProductManagement.Products { ????public class ProductAppService : ProductManagementAppService, IProductAppService ????{ ????????private readonly IRepository<Product, Guid> ?_productRepository; ????????public ProductAppService(IRepository<Product, Guid> productRepository) ????????{ ????????????_productRepository = productRepository; ????????} ????????public async Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input) ????????{ ????????????/* TODO: Implementation */ ????????} ????} } ``` `ProductAppService`派生自`ProductManagementAppService`,它在啟動模板中定義,可用作應用服務的基類。它實現了之前定義的`IProductAppService`接口,并注入`IRepository<Product, Guid>`服務。這就是通用**默認存儲**庫,方面我們對數據庫執行操作(ABP 自動為所有聚合根實體提供默認存儲庫實現)。 我們實現`GetListAsync`方法,如下代碼塊所示: ``` public async Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input) { ????var queryable = await _productRepository.WithDetailsAsync(x => x.Category); ????queryable = queryable ????????.Skip(input.SkipCount) ????????.Take(input.MaxResultCount) ????????.OrderBy(input.Sorting ?? nameof(Product.Name)); ????var products = await AsyncExecuter.ToListAsync(queryable); ????var count = await _productRepository.GetCountAsync(); ????return new PagedResultDto<ProductDto>( ????????count, ????????ObjectMapper.Map<List<Product>, List<ProductDto>>(products) ????); } ``` 這里,`_productRepository.WithDetailsAsync`返回一個包含產品類別的`IQueryable<Product>`對象,(`WithDetailsAsync`方法類似于 EF Core 的`Include`擴展方法,用于將相關數據加載到查詢中)。于是,我們就可以方便地使用標準的(**LINQ**) 擴展方法,比如`Skip`、`Take`和`OrderBy`等。 `AsyncExecuter`服務(基類中預先注入)用于執行`IQueryable`對象,這使得可以使用異步 LINQ 擴展方法執行數據庫查詢,而無需依賴應用程序層中的 EF Core 包。(我們將在\[*第 6 章* \] 中對`AsyncExecuter`進行更詳細的探討) 最后,我們使用`ObjectMapper`服務(在基類中預先注入)將`Product`集合映射到`ProductDto`集合。 ## 對象映射 `ObjectMapper`(`IObjectMapper`)會自動使用**AutoMapper**庫進行類型轉換。它要求我們在使用之前預先定義映射關系。啟動模板包含一個配置文件類,您可以在其中創建映射。 在ProductManage.Application項目中打開`ProductManagementApplicationAutoMapperProfile`類,并將其更改為以下內容: ``` using AutoMapper; using ProductManagement.Products; namespace ProductManagement { ????public class ProductManagementApplicationAutoMapperProfile : Profile ????{ ????????public ProductManagementApplicationAutoMapperProfile() ????????{ ????????????CreateMap<Product, ProductDto>(); ????????} ????} } ``` 如`CreateMap`所定義的映射。它可以自動將`Product`轉換為`ProductDto`對象。 AutoMapper中有一個有趣的功能:**Flattening**,它默認會將復雜的對象模型展平為更簡單的模型。在這個例子中,`Product`類有一個`Category`屬性,而`Category`類也有一個`Name`屬性。因此,如果要訪問產品的類別名稱,則應使用`Product.Category.Name`表達式。但是,`ProductDto`的`CategoryName`可以直接使用`ProductDto.CategoryName`表達式進行訪問。AutoMapper 會通過展平`Category.Name`來自動映射成`CategoryName`。 應用層服務已經基本完成。在開始 UI 之前,我們先介紹如何為應用層編寫自動化測試。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看