iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Software Development

DDD? Clean Architecture? Microservices? 帶你用.NET實作打造一個現代化微服務!系列 第 18

Day 18 - Todo Service 實作:利用 Quick Fix 快速完成 Finish/Remove Functions

  • 分享至 

  • xImage
  •  

Todo Service 回顧

Finish 和 Remove 都僅只是改變 Item 的 Status 而已,一起做完加快進度。

https://ithelp.ithome.com.tw/upload/images/20241002/20168953HFAhQw6WFt.png

todoItem.proto 實作

這邊我的 TodoItem 和 TodoList 的各項操作都是回傳 List 與 Item 本體,這可以自行調整想要的 Response。

syntax = "proto3";

option csharp_namespace = "Todo.Grpc";

service TodoItemGrpcService {
  rpc CreateTodoItem (CreateTodoItemRequest) returns (TodoItemResponse);
  rpc FinishTodoItem (FinishTodoItemRequest) returns (TodoItemResponse);
  rpc RemoveTodoItem (RemoveTodoItemRequest) returns (TodoItemResponse);
}

message CreateTodoItemRequest {
  string ListId = 1;
  string Content = 2;
}

message FinishTodoItemRequest {
  string Id = 1;
}

message RemoveTodoItemRequest {
  string Id = 1;
}

message TodoItemResponse {
  string Id = 1;
  string ListId = 2;
  string Content = 3;
  string Status = 4;
  string Color = 5;
}

加速 Tips

怕一直寫一樣的東西,文章會太無趣,這邊教大家如何用 VS Code 快速產生程式碼吧!接下來的實作會附上一些圖示教學,這裡用到的 Shortcuts 都是 VS Code Default。

GrpcTodoItemService 實作 FinishTodoItem 和 RemoveTodoItem

看到上述的 CreateTodoItemRequest FinishTodoItemRequest RemoveTodoItemRequest 相似到不行,就知道大概可以使用複製貼上了。

不過搭配一些 Tips,可以更加快速。

寫上 override 以後按下 space 就可以看到想要 override 的 Method。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953I0NdHbaUpN.png

選擇想要 override 的 Method 後就自動產生基本架構。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953oCvt7eNYpQ.png

因為 CreateTodoItemRequest FinishTodoItemRequest RemoveTodoItemRequest 相似,我們直接把 Code 複製下來,並且把 TodoItemService 的 Method 改成想要的名稱跟 Payload。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953gJYoGZfFop.png

到這邊就把 GrpcTodoItemService 實作完成,結果如下:

using Grpc.Core;
using Todo.Application;

namespace Todo.Grpc.Services;

public class GrpcTodoItemService : TodoItemGrpcService.TodoItemGrpcServiceBase
{
    private readonly ITodoItemService _todoItemService;

    public GrpcTodoItemService(ITodoItemService todoItemService)
    {
        this._todoItemService = todoItemService;
    }

    public override Task<TodoItemResponse> CreateTodoItem(CreateTodoItemRequest request, ServerCallContext context)
    {
        var result = _todoItemService.CreateTodoItem(new Guid(request.ListId), request.Content);

        TodoItemResponse response = new()
        {
            Id = result.Id.ToString(),
            ListId = result.ListId.ToString(),
            Content = result.Content,
            Status = result.Status.State.ToString(),
            Color = result.Status.Color
        };
    
        return Task.FromResult(response);
    }

    public override Task<TodoItemResponse> FinishTodoItem(FinishTodoItemRequest request, ServerCallContext context)
    {
        var result = _todoItemService.FinishTodoItem(new Guid(request.Id));

        TodoItemResponse response = new()
        {
            Id = result.Id.ToString(),
            ListId = result.ListId.ToString(),
            Content = result.Content,
            Status = result.Status.State.ToString(),
            Color = result.Status.Color
        };
    
        return Task.FromResult(response);
    }

    public override Task<TodoItemResponse> RemoveTodoItem(RemoveTodoItemRequest request, ServerCallContext context)
    {
        var result = _todoItemService.RemoveTodoItem(new Guid(request.Id));

        TodoItemResponse response = new()
        {
            Id = result.Id.ToString(),
            ListId = result.ListId.ToString(),
            Content = result.Content,
            Status = result.Status.State.ToString(),
            Color = result.Status.Color
        };
    
        return Task.FromResult(response);
    }
}

實作 TodoItemService

接著會發現有紅色蚯蚓提示我們 ITodoItemService 沒有這些 Methods。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953evpJ43XHYu.png

ITodoItemService

這時候對著紅色蚯蚓提示按下 ctrl + . 來選擇建議修正,這時選擇 Generate Method。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953J9hmos4vCq.png

之後就會發現 ITodoItemService 自動產生了對應的方法,因為我們是用 var 來宣告 result,所以這裡的回傳會是 object,把它修正回來即可。

https://ithelp.ithome.com.tw/upload/images/20240930/201689538NnIhoDb7N.png

結果:

namespace Todo.Application;

public interface ITodoItemService
{
    TodoItemResult CreateTodoItem(Guid listId, string content);
    TodoItemResult FinishTodoItem(Guid guid);
    TodoItemResult RemoveTodoItem(Guid guid);
}

TodoItemService

接著我們會發現先前的 TodoItemService 並沒有實作新的發法產生錯誤。一樣在紅色蚯蚓的地方按下 ctrl + . 來選擇 Implement interface。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953PFzxac5ApA.png

之後我們會看到系統自動產生好了對應的實作方法。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953lAtE9HHyYw.png

我們只需要把邏輯寫進去即可,結果如下:

using Todo.Domain.Aggregates;
using Todo.Domain.ValueObjects;

namespace Todo.Application;

public class TodoItemService : ITodoItemService
{
    private static readonly List<TodoItem> _todoItems = new();
    
    public TodoItemResult CreateTodoItem(Guid userId, string content)
    {
        var item = TodoItem.Create(content, userId);

        _todoItems.Add(item);

        return new TodoItemResult(item.Id.Value, item.ListId, item.Content, item.Status);
    }

    public TodoItemResult FinishTodoItem(Guid guid)
    {
        var item = _todoItems.SingleOrDefault(i => i.Id.Value == guid);

        if (item == null)
            throw new ArgumentException("Todo item not exists");
        if (item.Status != new TodoItemStatus(Domain.ValueObjects.Enums.TodoItemState.Todo))
            throw new ArgumentException("Todo item cannot be finished");

        item.MarkAsFinished();
        
        return new TodoItemResult(item.Id.Value, item.ListId, item.Content, item.Status);
    }

    public TodoItemResult RemoveTodoItem(Guid guid)
    {
        var item = _todoItems.SingleOrDefault(i => i.Id.Value == guid);

        if (item == null)
            throw new ArgumentException("Todo item not exists");

        item.Remove();
        
        return new TodoItemResult(item.Id.Value, item.ListId, item.Content, item.Status);
    }
}

Test

gRPC Clicker Test

重新整理一下,就可以看到剛剛實作的 Finish 和 Remove 已經出現在這。

https://ithelp.ithome.com.tw/upload/images/20240930/20168953qA0PElhAwt.png

是不是很神奇,從開始到完成,就只花了五分鐘的時間就寫好了兩個相似的功能,這就是為什麼你隔壁的 Senior 同事常常在上班偷懶的原因。

測試一下

  1. 新增 Todo List
    https://ithelp.ithome.com.tw/upload/images/20240930/20168953mmJjhhWfY9.png
  2. 新增 Todo Item,狀態 Todo
    https://ithelp.ithome.com.tw/upload/images/20240930/20168953rrOVpikyIh.png
  3. 完成 Todo Item,狀態 Finished
    https://ithelp.ithome.com.tw/upload/images/20240930/20168953VYr3C8MlKi.png
  4. 刪除 Todo Item,狀態 Removed
    https://ithelp.ithome.com.tw/upload/images/20240930/20168953ACGWLQlFMo.png

結語

細心的讀者看到這裡應該不難發現,我從最初 Account Service 的實作,都是由 Presentation Layer 開始實作,有很大的原因是因為我都用快捷鍵來自動產生物件和其方法,這節省了不少的開發時間。

另外有興趣的還可以安裝 Vim 套件讓這件事更便利快捷,但這需要花很多時間熟悉 Vim 的語法。

我們最後還有一個 Remove List 的功能要做,就當作業吧,沒意外應該也是 5 分鐘的事情。

那今天就先到這囉。


上一篇
Day 17 - Todo Service 實作:一次完成 Create List 和 Create Item
下一篇
Day 19 - Todo Infrastructure 實作:Repository Pattern 介紹
系列文
DDD? Clean Architecture? Microservices? 帶你用.NET實作打造一個現代化微服務!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言