Triển khai gRPC trong .NET: Xử lý Yêu cầu và Dòng Dữ liệu

Cấu trúc Protocol Buffer cơ bản

Để sử dụng kiểu dữ liệu rỗng, cần khai báo thư viện:

import "google/protobuf/empty.proto";

Kiểu dữ liệu rỗng được định nghĩa là google.protobuf.Empty. Với mảng, sử dụng từ khóa repeated.

Mẫu tệp .proto tiêu chuẩn

syntax = "proto3";
option csharp_namespace = "UserManagementService";
package usermgmt;

import "google/protobuf/empty.proto";

service UserManagement {
  rpc FetchAllUsers(Empty) returns (UserListResponse);
  rpc GetUserProfile(GetUserRequest) returns (UserProfileResponse);
  rpc UpdateUserStream(stream UserUpdateRequest) returns (UpdateResult);
  rpc CreateBidirectionalStream(stream UserCreationRequest) returns (stream CreationStatus);
  rpc StreamUserDetails(Empty) returns (stream UserDetails);
}

message GetUserRequest {
  string username = 1;
}

message UserProfileResponse {
  UserProfile user = 1;
}

message UserListResponse {
  repeated UserProfile users = 1;
}

message UserProfile {
  string name = 1;
  int32 age = 2;
}

message UserUpdateRequest {
  UserProfile profile = 1;
}

message UpdateResult {
  bool success = 1;
}

message UserCreationRequest {
  string action = 1;
  UserProfile data = 2;
}

message CreationStatus {
  bool status = 1;
}

message UserDetails {
  UserProfile profile = 1;
  string info = 2;
}

Cài đặt phía máy chủ

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using UserManagementService;

namespace UserApiService.Services
{
    public class UserService : UserManagement.UserManagementBase
    {
        public override async Task StreamUserDetails(Empty request, 
            IServerStreamWriter<UserDetails> responseStream, 
            ServerCallContext context)
        {
            await responseStream.WriteAsync(new UserDetails {
                Info = "Dữ liệu mẫu",
                Profile = new UserProfile { Name = "Nguyễn Văn A", Age = 30 }
            });
        }

        public override async Task<UpdateResult> UpdateUserStream(
            IAsyncStreamReader<UserUpdateRequest> requestStream,
            ServerCallContext context)
        {
            UserProfile latestProfile = null;
            await foreach (var update in requestStream.ReadAllAsync())
            {
                latestProfile = update.Profile;
            }
            return new UpdateResult { Success = latestProfile != null };
        }

        public override async Task FetchAllUsers(Empty request, 
            ServerCallContext context)
        {
            var response = new UserListResponse();
            response.Users.Add(new UserProfile { Name = "User 1", Age = 25 });
            response.Users.Add(new UserProfile { Name = "User 2", Age = 35 });
            return response;
        }
    }
}

Cấu hình phía máy khách

Trong tệp dự án client, cập nhật cấu hình:

<ItemGroup>
  <Protobuf Include="Protos\usermgmt.proto" GrpcServices="Client" />
</ItemGroup>

Đăng ký dịch vụ trong Program.cs:

builder.Services.AddGrpcClient<UserManagement.UserManagementClient>(options =>
{
    options.Address = new Uri("http://localhost:5000");
});

Gọi dịch vụ từ ứng dụng WebAPI

using Microsoft.AspNetCore.Mvc;
using UserManagementService;
using Google.Protobuf.WellKnownTypes;

namespace UserClientApi.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {
        private readonly UserManagementClient _client;

        public UserController(UserManagementClient client) 
            => _client = client;

        [HttpGet("all")]
        public IActionResult GetAllUsers()
        {
            var response = _client.FetchAllUsers(new Empty());
            return Ok(response.Users);
        }

        [HttpPost("stream")]
        public async Task<IActionResult> CreateUserStream()
        {
            var call = _client.CreateBidirectionalStream();
            await call.RequestStream.WriteAsync(new UserCreationRequest {
                Action = "CREATE",
                Data = new UserProfile { Name = "Minh", Age = 28 }
            });
            await call.RequestStream.CompleteAsync();
            
            await foreach (var status in call.ResponseStream.ReadAllAsync())
            {
                if (status.Status) return Ok("Thành công");
            }
            return BadRequest();
        }
    }
}

Thẻ: grpc protobuf dotnet aspnetcore streaming

Đăng vào ngày 20 tháng 5 lúc 00:15