前言,全文干货,需要知道和理解Grpc的基础上操作,全文仅记录代码过程,有疑问请留言!
一、创建Grpc服务
1、创建Grpc服务应用程序(PS:如何创建我就不细说了,不会的童鞋去看别的教程吧。)
2、编写Protos文件和服务
(1)在项目中创建文件夹Protos
(2)并创建文件Teacher.proto
可以理解为我们普通的Csharp代码的Interface接口,IService,用于编写服务接口
(3)依赖项中,分别添加Nugget程序包
(4)在项目中右键依赖性->管理连接的服务,并且配置grpc的服务teacher为服务器,这样就Protos文件就配置好了
(5)在项目中创建文件夹Services
(6)Service文件内容
定义了静态数据List<TeacherInfo> 方便测试和讲解,实际情况中会通过注入IRepository的方式来进行获取数据。
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
namespace GrpcService.Services
{
public class TeacherService : Teacher.TeacherBase
{
private readonly ILogger<TeacherService> _logger;
private static readonly List<TeacherInfo> _teacherInfos = new List<TeacherInfo>()
{
new TeacherInfo() { Id = "1", Name = "张三", Card = "zs", DeptId = "1", DeptName = "信息部" },
new TeacherInfo() { Id = "2", Name = "李四", Card = "ls", DeptId = "1", DeptName = "信息部" },
new TeacherInfo() { Id = "3", Name = "王五", Card = "ww", DeptId = "2", DeptName = "政治部" }
};
public TeacherService(ILogger<TeacherService> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public override Task<TeacherInfoResult> GetById(TeacherId request, ServerCallContext context)
{
_logger.LogInformation(context.RequestHeaders.GetValue("Authorization"));
var teacherInfo = _teacherInfos.FirstOrDefault(p => p.Id == request.Id);
var result = new TeacherInfoResult()
{
TeacherId = teacherInfo.Id,
TeacherCard = teacherInfo.Card,
TeacherName = teacherInfo.Name,
DepartmentId = teacherInfo.DeptId,
DepartmentName = teacherInfo.DeptName
};
return Task.FromResult(result);
}
public override Task<TeacherInfoResult> GetByToken(Empty request, ServerCallContext context)
{
var userId = context.RequestHeaders.GetValue("UserId");
var teacherInfo = _teacherInfos.FirstOrDefault(p => p.Id == userId);
var result = new TeacherInfoResult()
{
TeacherId = teacherInfo.Id,
TeacherCard = teacherInfo.Card,
TeacherName = teacherInfo.Name,
DepartmentId = teacherInfo.DeptId,
DepartmentName = teacherInfo.DeptName
};
return Task.FromResult(result);
}
}
public record TeacherInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string Card { get; set; }
public string DeptId { get; set; }
public string DeptName { get; set; }
}
}
3、注入文件
通过builder.Services.AddGrpc(); 添加服务
通过app.MapGrpcService<TeacherService>(); 配置服务
这样并搭建好了服务
二、配置Grpc客户端
1、创建ASC .NET Core Web API服务(PS:相信研究Grpc的小伙计们这么简单的操作还是会的,不过多余的讲解了)。
2、配置Grpc客户端
(1)依赖项中,分别添加Nugget程序包
(2)Copy写好的Protos文件,并修改为Teacher服务为客户端
直接复制,前面写好Teacher.Protos文件到Client中使用,实际项目开发中也是复制粘贴!
(3)Program中添加自定义服务类builder.Services.AddGrapcServiceConfiguration(builder.Configuration);
源码如下
public static class GrpcServiceExtensions
{
public static void AddGrapcServiceConfiguration(this IServiceCollection services, IConfiguration configuration)
{
services.AddGrpcClient<Teacher.TeacherClient>(options =>
{
options.Address = new Uri(configuration.GetValue<string>("GrpcUrls:FindTeacher"));
});
}
}
(4)appsetings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"GrpcUrls": {
"FindTeacher": "https://localhost:7108"
}
}
3、Controller中编写
[Route("api/[controller]/[action]")]
[ApiController]
public class GrpcTeacherController : ControllerBase
{
private readonly Teacher.TeacherClient _client;
public GrpcTeacherController(Teacher.TeacherClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}
[HttpGet]
public async Task<ActionResult> GetTeacher()
{
var reply = await _client.GetByIdAsync(new TeacherId { Id = "1" });
return Ok(reply);
}
[HttpGet]
public async Task<ActionResult> GetTeacherByToken()
{
//var authorization = _httpContextAccessor?.HttpContext?.Request.Headers["Authorization"];
var headers = new Metadata { { "UserId", "1" } };
var reply = await _client.GetByTokenAsync(request: new Empty(), headers);
return Ok(reply);
}
}
4、调用结果
三、配置统一配置JWT鉴权Token
public class AuthInterceptor : Interceptor
{
private readonly ILogger<AuthInterceptor> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public AuthInterceptor(ILogger<AuthInterceptor> logger, IHttpContextAccessor httpContextAccessor)
{
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var authorization = _httpContextAccessor?.HttpContext?.Request?.Headers["Authorization"].ToString();
var token = string.IsNullOrEmpty(authorization) ? "" : authorization.Remove(0, 7);
var metadata = new Metadata
{
{ "Authorization", $"Bearer {token}" }
};
var newContext = new ClientInterceptorContext<TRequest, TResponse>(
context.Method,
context.Host,
context.Options.WithHeaders(
(context.Options.Headers ?? new Metadata()).Aggregate(
metadata,
AddIfNonExistent))
);
return continuation(request, newContext);
}
private static Metadata AddIfNonExistent(Metadata metadata, Metadata.Entry entry)
{
if (metadata.Get(entry.Key) == null) metadata.Add(entry);
return metadata;
}
}
public static class GrpcServiceExtensions
{
public static void AddGrapcServiceConfiguration(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<AuthInterceptor>();
services.AddGrpcClient<Teacher.TeacherClient>(options =>
{
options.Address = new Uri(configuration.GetValue<string>("GrpcUrls:FindTeacher"));
}).AddInterceptor<AuthInterceptor>();
}
}