1. 程式人生 > >基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(五)

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(五)

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 給專案瘦身,讓它跑起來](https://www.cnblogs.com/meowv/p/12896898.html)** 3. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 完善與美化,Swagger登場](https://www.cnblogs.com/meowv/p/12909558.html)** 4. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 資料訪問和程式碼優先](https://www.cnblogs.com/meowv/p/12913676.html)** 5. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 自定義倉儲之增刪改查](https://www.cnblogs.com/meowv/p/12916613.html)** 6. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 統一規範API,包裝返回模型](https://www.cnblogs.com/meowv/p/12924409.html)** 7. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 再說Swagger,分組、描述、小綠鎖](https://www.cnblogs.com/meowv/p/12924859.html)** 8. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 接入GitHub,用JWT保護你的API](https://www.cnblogs.com/meowv/p/12935693.html)** 9. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 異常處理和日誌記錄](https://www.cnblogs.com/meowv/p/12943699.html)** 10. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用Redis快取資料](https://www.cnblogs.com/meowv/p/12956696.html)** 11. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 整合Hangfire實現定時任務處理](https://www.cnblogs.com/meowv/p/12961014.html)** 12. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 用AutoMapper搞定物件對映](https://www.cnblogs.com/meowv/p/12966092.html)** 13. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(一)](https://www.cnblogs.com/meowv/p/12971041.html)** 14. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(二)](https://www.cnblogs.com/meowv/p/12974439.html)** 15. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(三)](https://www.cnblogs.com/meowv/p/12980301.html)** 16. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(一)](https://www.cnblogs.com/meowv/p/12987623.html)** 17. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(二)](https://www.cnblogs.com/meowv/p/12994914.html)** 18. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(三)](https://www.cnblogs.com/meowv/p/13039883.html)** 19. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(四)](https://www.cnblogs.com/meowv/p/13043084.html)** --- [上篇文章](https://www.cnblogs.com/meowv/p/13043084.html)完成了文章詳情頁資料查詢和清除快取的功能。 本篇繼續完成分類、標籤、友情連結的後臺操作介面,還是那句話,這些純CRUD的內容,建議還是自己動手完成比較好,本篇將不再囉嗦,直接貼程式碼,以供參考。 ## 分類 新增介面:查詢分類列表`QueryCategoriesForAdminAsync()`、新增分類`InsertCategoryAsync(...)`、更新分類`UpdateCategoryAsync(...)`、刪除分類`DeleteCategoryAsync(...)` ```CSharp #region Categories /// /// 查詢分類列表 /// /// Task>> QueryCategoriesForAdminAsync(); /// /// 新增分類 /// /// /// Task InsertCategoryAsync(EditCategoryInput input); /// /// 更新分類 /// /// /// /// Task UpdateCategoryAsync(int id, EditCategoryInput input); /// /// 刪除分類 /// /// /// Task DeleteCategoryAsync(int id); #endregion Categories ``` 查詢分類列表需要返回的模型類`QueryCategoryForAdminDto.cs`。 ```CSharp //QueryCategoryForAdminDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class QueryCategoryForAdminDto : QueryCategoryDto { /// /// 主鍵 ///
public int Id { get; set; } } } ``` 新增分類和更新分類需要的輸入引數`EditCategoryInput.cs`,直接繼承`CategoryDto`即可。 ```CSharp //EditCategoryInput.cs namespace Meowv.Blog.Application.Contracts.Blog.Params { public class EditCategoryInput : CategoryDto { } } ``` 分別實現這幾個介面。 ```CSharp /// /// 查詢分類列表 ///
/// public async Task>> QueryCategoriesForAdminAsync() { var result = new ServiceResult>(); var posts = await _postRepository.GetListAsync(); var categories = _categoryRepository.GetListAsync().Result.Select(x => new QueryCategoryForAdminDto { Id = x.Id, CategoryName = x.CategoryName, DisplayName = x.DisplayName, Count = posts.Count(p => p.CategoryId == x.Id) }); result.IsSuccess(categories); return result; } ``` ```CSharp /// /// 新增分類 ///
/// /// public async Task InsertCategoryAsync(EditCategoryInput input) { var result = new ServiceResult(); var category = ObjectMapper.Map(input); await _categoryRepository.InsertAsync(category); result.IsSuccess(ResponseText.INSERT_SUCCESS); return result; } ``` 這裡需要一條AutoMapper配置,將`EditCategoryInput`轉換為`Category`,忽略Id欄位。 ```CSharp CreateMap().ForMember(x => x.Id, opt => opt.Ignore()); ``` ```CSharp /// /// 更新分類 /// /// /// /// public async Task UpdateCategoryAsync(int id, EditCategoryInput input) { var result = new ServiceResult(); var category = await _categoryRepository.GetAsync(id); category.CategoryName = input.CategoryName; category.DisplayName = input.DisplayName; await _categoryRepository.UpdateAsync(category); result.IsSuccess(ResponseText.UPDATE_SUCCESS); return result; } ``` ```CSharp /// /// 刪除分類 /// /// /// public async Task DeleteCategoryAsync(int id) { var result = new ServiceResult(); var category = await _categoryRepository.FindAsync(id); if (null == category) { result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("Id", id)); return result; } await _categoryRepository.DeleteAsync(id); result.IsSuccess(ResponseText.DELETE_SUCCESS); return result; } ``` 在`BlogController.Admin.cs`中新增介面。 ```CSharp #region Categories /// /// 查詢分類列表 /// /// [HttpGet] [Authorize] [Route("admin/categories")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task>> QueryCategoriesForAdminAsync() { return await _blogService.QueryCategoriesForAdminAsync(); } /// /// 新增分類 /// /// /// [HttpPost] [Authorize] [Route("category")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task InsertCategoryAsync([FromBody] EditCategoryInput input) { return await _blogService.InsertCategoryAsync(input); } /// /// 更新分類 /// /// /// /// [HttpPut] [Authorize] [Route("category")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task UpdateCategoryAsync([Required] int id, [FromBody] EditCategoryInput input) { return await _blogService.UpdateCategoryAsync(id, input); } /// /// 刪除分類 /// /// /// [HttpDelete] [Authorize] [Route("category")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task DeleteCategoryAsync([Required] int id) { return await _blogService.DeleteCategoryAsync(id); } #endregion Categories ``` ![0](https://img2020.cnblogs.com/blog/891843/202006/891843-20200605101020914-137049974.png) ## 標籤 新增介面:查詢標籤列表`QueryTagsForAdminAsync()`、新增標籤`InsertTagAsync(...)`、更新標籤`UpdateTagAsync(...)`、刪除標籤`DeleteTagAsync(...)` ```CSharp #region Tags /// /// 查詢標籤列表 /// /// Task>> QueryTagsForAdminAsync(); /// /// 新增標籤 /// /// /// Task InsertTagAsync(EditTagInput input); /// /// 更新標籤 /// /// /// /// Task UpdateTagAsync(int id, EditTagInput input); /// /// 刪除標籤 /// /// /// Task DeleteTagAsync(int id); #endregion Tags ``` 查詢標籤列表需要返回的模型類`QueryTagForAdminDto.cs`。 ```CSharp //QueryTagForAdminDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class QueryTagForAdminDto : QueryTagDto { /// /// 主鍵 /// public int Id { get; set; } } } ``` 新增標籤和更新標籤需要的輸入引數`EditTagInput.cs`,直接繼承`TagDto`即可。 ```CSharp //EditTagInput.cs namespace Meowv.Blog.Application.Contracts.Blog.Params { public class EditTagInput : TagDto { } } ``` 分別實現這幾個介面。 ```CSharp /// /// 查詢標籤列表 /// /// public async Task>> QueryTagsForAdminAsync() { var result = new ServiceResult>(); var post_tags = await _postTagRepository.GetListAsync(); var tags = _tagRepository.GetListAsync().Result.Select(x => new QueryTagForAdminDto { Id = x.Id, TagName = x.TagName, DisplayName = x.DisplayName, Count = post_tags.Count(p => p.TagId == x.Id) }); result.IsSuccess(tags); return result; } ``` ```CSharp /// /// 新增標籤 /// /// /// public async Task InsertTagAsync(EditTagInput input) { var result = new ServiceResult(); var tag = ObjectMapper.Map(input); await _tagRepository.InsertAsync(tag); result.IsSuccess(ResponseText.INSERT_SUCCESS); return result; } ``` 這裡需要一條AutoMapper配置,將`EditCategoryInput`轉換為`Tag`,忽略Id欄位。 ```CSharp CreateMap().ForMember(x => x.Id, opt => opt.Ignore()); ``` ```CSharp /// /// 更新標籤 /// /// /// /// public async Task UpdateTagAsync(int id, EditTagInput input) { var result = new ServiceResult(); var tag = await _tagRepository.GetAsync(id); tag.TagName = input.TagName; tag.DisplayName = input.DisplayName; await _tagRepository.UpdateAsync(tag); result.IsSuccess(ResponseText.UPDATE_SUCCESS); return result; } ``` ```CSharp /// /// 刪除標籤 /// /// /// public async Task DeleteTagAsync(int id) { var result = new ServiceResult(); var tag = await _tagRepository.FindAsync(id); if (null == tag) { result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("Id", id)); return result; } await _tagRepository.DeleteAsync(id); await _postTagRepository.DeleteAsync(x => x.TagId == id); result.IsSuccess(ResponseText.DELETE_SUCCESS); return result; } ``` 在`BlogController.Admin.cs`中新增介面。 ```CSharp #region Tags /// /// 查詢標籤列表 /// /// [HttpGet] [Authorize] [Route("admin/tags")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task>> QueryTagsForAdminAsync() { return await _blogService.QueryTagsForAdminAsync(); } /// /// 新增標籤 /// /// /// [HttpPost] [Authorize] [Route("tag")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task InsertTagAsync([FromBody] EditTagInput input) { return await _blogService.InsertTagAsync(input); } /// /// 更新標籤 /// /// /// /// [HttpPut] [Authorize] [Route("tag")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task UpdateTagAsync([Required] int id, [FromBody] EditTagInput input) { return await _blogService.UpdateTagAsync(id, input); } /// /// 刪除標籤 /// /// /// [HttpDelete] [Authorize] [Route("tag")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task DeleteTagAsync([Required] int id) { return await _blogService.DeleteTagAsync(id); } #endregion Tags ``` ![1](https://img2020.cnblogs.com/blog/891843/202006/891843-20200605101101841-106276175.png) ## 友鏈 新增介面:查詢友鏈列表`QueryFriendLinksForAdminAsync()`、新增友鏈`InsertFriendLinkAsync(...)`、更新友鏈`UpdateFriendLinkAsync(...)`、刪除友鏈`DeleteFriendLinkAsync(...)` ```CSharp #region FriendLinks /// /// 查詢友鏈列表 /// /// Task>> QueryFriendLinksForAdminAsync(); /// /// 新增友鏈 /// /// /// Task InsertFriendLinkAsync(EditFriendLinkInput input); /// /// 更新友鏈 /// /// /// /// Task UpdateFriendLinkAsync(int id, EditFriendLinkInput input); /// /// 刪除友鏈 /// /// /// Task DeleteFriendLinkAsync(int id); #endregion FriendLinks ``` 查詢友鏈列表需要返回的模型類`QueryFriendLinkForAdminDto.cs`。 ```CSharp //QueryFriendLinkForAdminDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class QueryFriendLinkForAdminDto : FriendLinkDto { /// /// 主鍵 /// public int Id { get; set; } } } ``` 新增友鏈和更新友鏈需要的輸入引數`EditFriendLinkInput.cs`,直接繼承`FriendLinkDto`即可。 ```CSharp //EditFriendLinkInput .cs namespace Meowv.Blog.Application.Contracts.Blog.Params { public class EditFriendLinkInput : FriendLinkDto { } } ``` 分別實現這幾個介面。 ```CSharp /// /// 查詢友鏈列表 /// /// public async Task>> QueryFriendLinksForAdminAsync() { var result = new ServiceResult>(); var friendLinks = await _friendLinksRepository.GetListAsync(); var dto = ObjectMapper.Map, IEnumerable>(friendLinks); result.IsSuccess(dto); return result; } ``` ```CSharp /// /// 新增友鏈 /// /// /// public async Task InsertFriendLinkAsync(EditFriendLinkInput input) { var result = new ServiceResult(); var friendLink = ObjectMapper.Map(input); await _friendLinksRepository.InsertAsync(friendLink); // 執行清除快取操作 await _blogCacheService.RemoveAsync(CachePrefix.Blog_FriendLink); result.IsSuccess(ResponseText.INSERT_SUCCESS); return result; } ``` ```CSharp /// /// 更新友鏈 /// /// /// /// public async Task UpdateFriendLinkAsync(int id, EditFriendLinkInput input) { var result = new ServiceResult(); var friendLink = await _friendLinksRepository.GetAsync(id); friendLink.Title = input.Title; friendLink.LinkUrl = input.LinkUrl; await _friendLinksRepository.UpdateAsync(friendLink); // 執行清除快取操作 await _blogCacheService.RemoveAsync(CachePrefix.Blog_FriendLink); result.IsSuccess(ResponseText.UPDATE_SUCCESS); return result; } ``` ```CSharp /// /// 刪除友鏈 /// /// /// public async Task DeleteFriendLinkAsync(int id) { var result = new ServiceResult(); var friendLink = await _friendLinksRepository.FindAsync(id); if (null == friendLink) { result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("Id", id)); return result; } await _friendLinksRepository.DeleteAsync(id); // 執行清除快取操作 await _blogCacheService.RemoveAsync(CachePrefix.Blog_FriendLink); result.IsSuccess(ResponseText.DELETE_SUCCESS); return result; } ``` 其中查詢友鏈列表和新增友鏈中有兩條AutoMapper配置。 ```CSharp CreateMap(); CreateMap().ForMember(x => x.Id, opt => opt.Ignore()); ``` 在`BlogController.Admin.cs`中新增介面。 ```CSharp #region FriendLinks /// /// 查詢友鏈列表 /// /// [HttpGet] [Authorize] [Route("admin/friendlinks")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task>> QueryFriendLinksForAdminAsync() { return await _blogService.QueryFriendLinksForAdminAsync(); } /// /// 新增友鏈 /// /// /// [HttpPost] [Authorize] [Route("friendlink")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task InsertFriendLinkAsync([FromBody] EditFriendLinkInput input) { return await _blogService.InsertFriendLinkAsync(input); } /// /// 更新友鏈 /// /// /// /// [HttpPut] [Authorize] [Route("friendlink")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task UpdateFriendLinkAsync([Required] int id, [FromBody] EditFriendLinkInput input) { return await _blogService.UpdateFriendLinkAsync(id, input); } /// /// 刪除友鏈 /// /// /// [HttpDelete] [Authorize] [Route("friendlink")] [ApiExplorerSettings(GroupName = Grouping.GroupName_v2)] public async Task DeleteFriendLinkAsync([Required] int id) { return await _blogService.DeleteFriendLinkAsync(id); } #endregion ``` ![3](https://img2020.cnblogs.com/blog/891843/202006/891843-20200605101143054-44406883.png) ## Next 截止本篇,**基於 abp vNext 和 .NET Core 開發部落格專案** 系列的後臺API部分便全部開發完成了。 本部落格專案系列是我一邊寫程式碼一邊記錄後的成果,並不是開發完成後再拿出來寫的,涉及到東西也不是很多,對於新手入門來說應該是夠了的,如果你從中有所收穫請多多轉發分享。 在此,希望大家可以關注一下我的微信公眾號:『**阿星Plus**』,文章將會首發在公眾號中。 現在有了API,大家可以選擇自己熟悉的方式去開發前端介面,比如目前我部落格的線上版本就是用的 ASP.NET Core Web ,感興趣的可以去 `release` 分支檢視。 關於前端部分,看到有人呼籲vue,說實話前端技術不是很厲害,本職主要是後端開發,可能達不到預期效果。 所以我準備入坑 [Blazor](http://blazor.net/)