iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Software Development

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

Day 17 - Todo Service 實作:一次完成 Create List 和 Create Item

  • 分享至 

  • xImage
  •  

Todo Service 回顧

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

很多細節都與前幾篇在實作 Account Service 一致,這邊算是一個複習。我建議讀者可以試著自己寫看看。接下來我還是會照著 Coding 的順序來實作,但解釋會變少,有不理解的可以回去重溫 Account Service 的流程。

todoList.proto 實作

開新的 protobuf 記得要加入專案內,並設定為 Server。

  <ItemGroup>
    <Protobuf Include="Protos\todoList.proto" GrpcServices="Server" />
  </ItemGroup>

todoList.proto:

syntax = "proto3";

option csharp_namespace = "Todo.Grpc";

service TodoListGrpcService {
  rpc CreateTodoList (CreateTodoListRequest) returns (TodoListResponse);
}

message CreateTodoListRequest {
  string UserId = 1;
  string Name = 2;
  string Description = 3;
}

message TodoListResponse {
  string Id = 1;
  string UserId = 2;
  string Name = 3;
  string Description = 4;
  string Status = 5;
}

GrpcTodoListService 實作 CreateTodoList

Override gRPC 實作

using Grpc.Core;
using Todo.Application;

namespace Todo.Grpc.Services;

public class GrpcTodoListService : TodoListGrpcService.TodoListGrpcServiceBase
{
    private readonly ITodoListService _todoListService;

    public GrpcTodoListService(ITodoListService todoListService)
    {
        this._todoListService = todoListService;
    }

    public override Task<TodoListResponse> CreateTodoList(CreateTodoListRequest request, ServerCallContext context)
    {
        var result = _todoListService.CreateTodoList(new Guid(request.UserId), request.Name, request.Description);

        TodoListResponse response = new();

        return Task.FromResult(response);
    }
}

實作 TodoListService

ITodoListService

namespace Todo.Application;

public interface ITodoListService
{
    TodoListResult CreateTodoList(Guid userId, string name, string description);
}

TodoListResult

using Todo.Domain.ValueObjects.Enums;

namespace Todo.Application;

public record TodoListResult(
    Guid Id,
    Guid UserId,
    string Name,
    string Description,
    TodoListStatus Status
);

TodoListService

using Todo.Domain.Aggregates;

namespace Todo.Application;

public class TodoListService : ITodoListService
{
    private readonly List<TodoList> _todoLists = new();
    
    public TodoListResult CreateTodoList(Guid userId, string name, string description)
    {
        var list = TodoList.Create(name, description, userId);

        _todoLists.Add(list);

        return new TodoListResult(list.Id.Value, list.UserId, list.Name, list.Description, list.Status);
    }
}

GrpcTodoListService 補上 Response

public override Task<TodoListResponse> CreateTodoList(CreateTodoListRequest request, ServerCallContext context)
{
    var result = _todoListService.CreateTodoList(new Guid(request.UserId), request.Name, request.Description);

    TodoListResponse response = new()
    {
        Id = result.Id.ToString(),
        UserId = result.UserId.ToString(),
        Name = result.Name,
        Description = result.Description,
        Status = result.Status.ToString()
    };

    return Task.FromResult(response);
}

Register Service - Todo List

using Microsoft.Extensions.DependencyInjection;

namespace Todo.Application;

public static class TodoApplicationRegister
{
    public static IServiceCollection AddTodoApplication(this IServiceCollection services)
    {
        services.AddScoped<ITodoListService, TodoListService>();

        return services;
    }
}

Program.cs - Todo List

using Todo.Grpc.Services;
using Todo.Application;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddGrpcReflection();
builder.Services.AddTodoApplication();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService<GrpcTodoListService>();
app.MapGrpcReflectionService();

app.Run();

Test - CreateTodoList

dotnet run

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

gRPC Clicker Add Schema

這邊記得把 Timeout 填長一點,避免之後得一直改。

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

我們就可以看到新增的 CreateTodoList 的 Endpoint。

https://ithelp.ithome.com.tw/upload/images/20240930/201689532Su1fhj3BD.png

gRPC Clicker Test - CreateTodoList

測試一下,看來沒甚麼問題。

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

實作 Create Todo Item

繼續來實作 TodoItem 的 Create 方法,跟先前的做法差不多,大家可以先自行練習後在閱讀。

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

todoItem.proto 實作

開新的 protobuf 記得要加入專案內,並設定為 Server。

  <ItemGroup>
    <Protobuf Include="Protos\todoItem.proto" GrpcServices="Server" />    
    <Protobuf Include="Protos\todoList.proto" GrpcServices="Server" />
  </ItemGroup>

todoItem.proto:

syntax = "proto3";

option csharp_namespace = "Todo.Grpc";

service TodoItemGrpcService {
  rpc CreateTodoItem (CreateTodoItemRequest) returns (TodoItemResponse);
}

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

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

GrpcTodoItemService 實作 CreateTodoItem

Override gRPC 實作

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();
    
        return Task.FromResult(response);
    }
}

實作 TodoItemService

ITodoItemService

namespace Todo.Application;

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

TodoItemResult

using Todo.Domain.ValueObjects;

namespace Todo.Application;

public record TodoItemResult(
    Guid Id,
    Guid ListId,
    string Content,
    TodoItemStatus Status
);

TodoItemService


using Todo.Domain.Aggregates;

namespace Todo.Application;

public class TodoItemService : ITodoItemService
{
    private 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);
    }
}

GrpcTodoItemService 補上 Response

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);
}

Register Service - Todo Item

using Microsoft.Extensions.DependencyInjection;

namespace Todo.Application;

public static class TodoApplicationRegister
{
    public static IServiceCollection AddTodoApplication(this IServiceCollection services)
    {
        services.AddScoped<ITodoListService, TodoListService>();
        services.AddScoped<ITodoItemService, TodoItemService>();

        return services;
    }
}

Program.cs - Todo Item

app.MapGrpcService<GrpcTodoItemService>();

Test - CreateTodoItem

gRPC Clicker Test - CreateTodoItem

當 Map 一個新的 gRPC Service 後,Reflection 會讓 gRPC Clicker 知道有新的 Endpoint 和其 Payload。

https://ithelp.ithome.com.tw/upload/images/20240930/201689530dVJkat4P7.png

測試一下,OK 沒有問題,有正確的 Status 和 Color。

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

結語

附上目前為止的專案架構圖

https://ithelp.ithome.com.tw/upload/images/20240930/201689532mNR1PaZg7.png


上一篇
Day 16 - Account Infrastructure 實作:資料庫建置與 ORM 開發
下一篇
Day 18 - Todo Service 實作:利用 Quick Fix 快速完成 Finish/Remove Functions
系列文
DDD? Clean Architecture? Microservices? 帶你用.NET實作打造一個現代化微服務!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言