能否在.NET与Visual Studio中实现gRPC服务调用RESTful API及客户端对接?
完全可行!
在C#/.NET环境下实现「Razor客户端 → 自研gRPC服务 → 外部REST API」的架构是完全没问题的,.NET生态对gRPC的集成、REST API的调用都有成熟的工具链支持,下面是针对你的技术栈的分步示例:
1. 搭建自研gRPC服务
1.1 定义gRPC服务契约(.proto文件)
在gRPC服务项目中创建UserService.proto:
syntax = "proto3"; option csharp_namespace = "GrpcUserService"; package user; // 用户服务定义 service UserService { // 拉取用户信息 rpc GetUser (GetUserRequest) returns (UserResponse); // 更新用户信息 rpc UpdateUser (UpdateUserRequest) returns (UserResponse); // 删除用户 rpc DeleteUser (DeleteUserRequest) returns (DeleteUserResponse); } // 请求参数 message GetUserRequest { string user_id = 1; } message UpdateUserRequest { string user_id = 1; string name = 2; string email = 3; } message DeleteUserRequest { string user_id = 1; } // 响应数据 message UserResponse { string user_id = 1; string name = 2; string email = 3; string workday_status = 4; } message DeleteUserResponse { bool success = 1; string message = 2; }
1.2 实现gRPC服务并调用外部REST API
在gRPC服务项目中创建UserService.cs,注入HttpClient来调用Workday的REST API:
using Grpc.Core; using GrpcUserService; using System.Text.Json; public class UserServiceImpl : UserService.UserServiceBase { private readonly HttpClient _httpClient; private readonly IConfiguration _configuration; public UserServiceImpl(HttpClient httpClient, IConfiguration configuration) { _httpClient = httpClient; _configuration = configuration; } // 拉取用户:调用Workday REST API public override async Task<UserResponse> GetUser(GetUserRequest request, ServerCallContext context) { var workdayApiUrl = _configuration["Workday:ApiUrl"] + $"/users/{request.UserId}"; var authToken = _configuration["Workday:AuthToken"]; _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken); var response = await _httpClient.GetAsync(workdayApiUrl); response.EnsureSuccessStatusCode(); var workdayUser = await response.Content.ReadFromJsonAsync<WorkdayUserDto>(); return new UserResponse { UserId = workdayUser.Id, Name = workdayUser.FullName, Email = workdayUser.WorkEmail, WorkdayStatus = workdayUser.Status }; } // 更新用户:调用Workday REST API public override async Task<UserResponse> UpdateUser(UpdateUserRequest request, ServerCallContext context) { var workdayApiUrl = _configuration["Workday:ApiUrl"] + $"/users/{request.UserId}"; var authToken = _configuration["Workday:AuthToken"]; _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken); var updateData = new { fullName = request.Name, workEmail = request.Email }; var content = new StringContent(JsonSerializer.Serialize(updateData), System.Text.Encoding.UTF8, "application/json"); var response = await _httpClient.PutAsync(workdayApiUrl, content); response.EnsureSuccessStatusCode(); var updatedUser = await response.Content.ReadFromJsonAsync<WorkdayUserDto>(); return new UserResponse { UserId = updatedUser.Id, Name = updatedUser.FullName, Email = updatedUser.WorkEmail, WorkdayStatus = updatedUser.Status }; } // 删除用户:调用Workday REST API public override async Task<DeleteUserResponse> DeleteUser(DeleteUserRequest request, ServerCallContext context) { var workdayApiUrl = _configuration["Workday:ApiUrl"] + $"/users/{request.UserId}"; var authToken = _configuration["Workday:AuthToken"]; _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken); var response = await _httpClient.DeleteAsync(workdayApiUrl); if (response.IsSuccessStatusCode) { return new DeleteUserResponse { Success = true, Message = "用户删除成功" }; } else { var errorMsg = await response.Content.ReadAsStringAsync(); return new DeleteUserResponse { Success = false, Message = $"删除失败:{errorMsg}" }; } } } // 映射Workday返回的用户数据的DTO public class WorkdayUserDto { public string Id { get; set; } public string FullName { get; set; } public string WorkEmail { get; set; } public string Status { get; set; } }
1.3 配置gRPC服务
在Program.cs中注册服务和HttpClient:
var builder = WebApplication.CreateBuilder(args); // 添加gRPC服务 builder.Services.AddGrpc(); // 注册HttpClient用于调用外部REST API builder.Services.AddHttpClient(); var app = builder.Build(); // 映射gRPC服务端点 app.MapGrpcService<UserServiceImpl>(); app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client."); app.Run();
2. 在Razor项目中集成gRPC客户端
2.1 添加gRPC客户端包和服务引用
在Razor项目的NuGet包管理器中安装Grpc.Net.Client和Google.Protobuf,然后添加对gRPC服务项目的引用(或通过.proto文件生成客户端代码)。
2.2 配置gRPC客户端
在Razor项目的Program.cs中注册gRPC客户端:
var builder = WebApplication.CreateBuilder(args); // 添加Razor Pages服务 builder.Services.AddRazorPages(); // 注册gRPC客户端 builder.Services.AddGrpcClient<UserService.UserServiceClient>(options => { options.Address = new Uri(builder.Configuration["GrpcService:Url"]); // 配置文件中指定gRPC服务地址,例:http://localhost:5000 }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
2.3 在Razor页面中调用gRPC服务
创建UserManagement.cshtml.cs页面模型,注入gRPC客户端并实现调用:
using GrpcUserService; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; public class UserManagementModel : PageModel { private readonly UserService.UserServiceClient _grpcClient; public UserManagementModel(UserService.UserServiceClient grpcClient) { _grpcClient = grpcClient; } public UserResponse User { get; set; } public string OperationMessage { get; set; } // 拉取用户 public async Task OnGet(string userId) { User = await _grpcClient.GetUserAsync(new GetUserRequest { UserId = userId }); } // 更新用户 public async Task<IActionResult> OnPostUpdate(string userId, string name, string email) { var response = await _grpcClient.UpdateUserAsync(new UpdateUserRequest { UserId = userId, Name = name, Email = email }); OperationMessage = $"用户更新成功:{response.Name}"; return RedirectToPage(new { userId }); } // 删除用户 public async Task<IActionResult> OnPostDelete(string userId) { var response = await _grpcClient.DeleteUserAsync(new DeleteUserRequest { UserId = userId }); OperationMessage = response.Success ? "用户删除成功" : response.Message; return RedirectToPage(); } }
对应的Razor页面UserManagement.cshtml示例:
@page @model UserManagementModel <h1>用户管理</h1> @if (Model.User != null) { <div> <h3>用户信息</h3> <p>ID: @Model.User.UserId</p> <p>姓名: @Model.User.Name</p> <p>邮箱: @Model.User.Email</p> <p>Workday状态: @Model.User.WorkdayStatus</p> </div> <form method="post" asp-page-handler="Update"> <input type="hidden" name="userId" value="@Model.User.UserId" /> <div> <label>新姓名:</label> <input type="text" name="name" value="@Model.User.Name" /> </div> <div> <label>新邮箱:</label> <input type="email" name="email" value="@Model.User.Email" /> </div> <button type="submit">更新用户</button> </form> <form method="post" asp-page-handler="Delete" onsubmit="return confirm('确定要删除该用户吗?')"> <input type="hidden" name="userId" value="@Model.User.UserId" /> <button type="submit">删除用户</button> </form> } else { <form method="get"> <label>输入用户ID:</label> <input type="text" name="userId" /> <button type="submit">查询用户</button> </form> } @if (!string.IsNullOrEmpty(Model.OperationMessage)) { <p>@Model.OperationMessage</p> }
注意事项
- 确保gRPC服务和Razor项目的配置文件中正确填写Workday API的凭证、gRPC服务地址等敏感信息,建议使用.NET的机密管理器或环境变量存储,避免硬编码。
- 针对外部REST API的调用,可以添加重试、超时等策略,比如使用
Polly库增强HttpClient的可靠性。 - 生产环境中建议使用HTTPS保障gRPC服务与客户端之间的通信安全。
内容的提问来源于stack exchange,提问作者Rodrigo Escobar
相关产品推荐
相关产品推荐

