You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 22:04:53