脚本宝典收集整理的这篇文章主要介绍了源码解析Grpc拦截器(C#版本),脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
其实Grpc拦截器是我以前研究过,但是我看网上相关C#版本的源码解析相对少一点,所以笔者借这篇文章给大家分享下Grpc拦截器的实现,废话不多说,直接开讲(Grpc的源码看着很方便,包自动都能还原成功。.Net源码就硬生啃。。。弄了半天没还原成功😂)。 ps:
public abstract class Interceptor
{
//一元调用同步拦截器
public virtual TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
where TRequest : class
where TResponse : class
{
return continuation(request, context);
}
//一元调用异步拦截器
public virtual AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
where TRequest : class
where TResponse : class
{
return continuation(request, context);
}
}
public abstract class CallInvoker
{
//一元调用同步拦截器
public abstract TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
where TRequest : class
where TResponse : class;
//一元调用异步拦截器
public abstract AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
where TRequest : class
where TResponse : class;
}
首先我们要理解这两个抽象类分别是干什么的,上述代码讲解:
public static class CallInvokerextensions
{
//增加一个拦截器
public static CallInvoker Intercept(this CallInvoker invoker, Interceptor interceptor)
{
return new InterceptingCallInvoker(invoker, interceptor);
}
//增加一组拦截器
public static CallInvoker Intercept(this CallInvoker invoker, params Interceptor[] interceptors)
{
//检查是否为Null
GrpcPrecondITions.CheckNotNull(invoker, nameof(invoker));
GrpcPreconditions.CheckNotNull(interceptors, nameof(interceptors));
//反转集合,构造对象
foreach (VAR interceptor in interceptors.reverse())
{
invoker = Intercept(invoker, interceptor);
}
return invoker;
}
//篇幅原因,这种方式这里不进行讲解,大家可以自己翻下源码看下,主要作用就是增加用户自定义的额外报文值,类似Http请求中的Header
public static CallInvoker Intercept(this CallInvoker invoker, Func<metadata, Metadata> interceptor)
{
return new InterceptingCallInvoker(invoker, new Metadatainterceptor(interceptor));
}
}
上述代码总结:
internal class InterceptingCallInvoker : CallInvoker
{
//下一个invoker对象
readonly CallInvoker invoker;
//当前的拦截器
readonly Interceptor interceptor;
public InterceptingCallInvoker(CallInvoker invoker, Interceptor interceptor)
{
this.invoker = GrpcPreconditions.CheckNotNull(invoker, nameof(invoker));
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
}
//一元同步调用
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
{
return interceptor.BlockingUnaryCall(
request,
new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
//当前请求参数和上下文,调用下一个BlockingUnaryCall
(req, ctx) => invoker.BlockingUnaryCall(ctx.Method, ctx.Host, ctx.Options, req));
}
//一元异步调用
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
{
return interceptor.AsyncUnaryCall(
request,
new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
//当前请求参数和上下文,调用下一个BlockingUnaryCall
(req, ctx) => invoker.AsyncUnaryCall(ctx.Method, ctx.Host, ctx.Options, req));
}
}
//默认的CallInvoker,也就是不加任何拦截器时候的实现
public class DefaultCallInvoker : CallInvoker
{
readonly Channel channel;
public DefaultCallInvoker(Channel channel)
{
this.channel = GrpcPreconditions.CheckNotNull(channel);
}
//一元同步调用
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
{
var call = CreateCall(method, host, options);
return Calls.BlockingUnaryCall(call, request);
}
//一元异步调用
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
{
var call = CreateCall(method, host, options);
return Calls.AsyncUnaryCall(call, request);
}
}
上述代码总结:
public abstract class Interceptor
{
//服务端一元调用拦截器
public virtual Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
where TRequest : class
where TResponse : class
{
return continuation(request, context);
}
}
public class ServerServiceDefinition
{
//方法列表,也就是服务端写的那些方法
readonly IReadOnlyList<Action<ServiceBinderBase>> addMethodActions;
internal ServerServiceDefinition(List<Action<ServiceBinderBase>> addMethodActions)
{
this.addMethodActions = addMethodActions.AsReadOnly();
}
//给方法绑定服务,也就是绑定拦截器,一会的源码会提到
internal void BindService(ServiceBinderBase serviceBinder)
{
//给每个方法都绑定一下拦截器
foreach (var addMethodAction in addMethodActions)
{
addMethodAction(serviceBinder);
}
}
//创建Builder,可以在proto文件中生成的代码看到,会有调用这个方法
public static Builder CreateBuilder()
{
return new Builder();
}
public class Builder
{
//检测是否有同名方法,这是不被允许的
readonly Dictionary<string, object> duplicatedetector = new Dictionary<string, object>();
//服务端方法集合
readonly List<Action<ServiceBinderBase>> addMethodActions = new List<Action<ServiceBinderBase>>();
public Builder()
{
}
//可以看到在proto生成的代码中,有调用AddMethod,将方法添加到集合中
public Builder AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
where TRequest : class
where TResponse : class
{
duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this;
}
//这中间省略了除一元调用的其他调用,有兴趣的可以自己翻下源码
//初始化build,将上面的方法列表添加到其中
public ServerServiceDefinition Build()
{
return new ServerServiceDefinition(addMethodActions);
}
}
}
上述代码总结:
public static class ServerServiceDefinitionExtensions
{
//单个添加拦截器
public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, Interceptor interceptor)
{
GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
//构造新的ServiceBinder
var binder = new InterceptingServiceBinder(interceptor);
//将拦截器绑定到每个方法上
serverServiceDefinition.BindService(binder);
//生成并返回新的service
return binder.GetInterceptedServerServiceDefinition();
}
//添加一组拦截器
public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, params Interceptor[] interceptors)
{
GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
GrpcPreconditions.CheckNotNull(interceptors, nameof(interceptors));
foreach (var interceptor in interceptors.Reverse())
{
serverServiceDefinition = Intercept(serverServiceDefinition, interceptor);
}
return serverServiceDefinition;
}
//只保留了一元调用的代码
private class InterceptingServiceBinder : ServiceBinderBase
{
//创建一个空的Builder
readonly ServerServiceDefinition.Builder builder = ServerServiceDefinition.CreateBuilder();
//当前拦截器
readonly Interceptor interceptor;
public InterceptingServiceBinder(Interceptor interceptor)
{
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
}
//构造新的Builder
internal ServerServiceDefinition GetInterceptedServerServiceDefinition()
{
return builder.Build();
}
//添加一元调用的方法,而这个就是你自定义的拦截器
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
{
builder.AddMethod(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler));
}
//这里省略了一部分代码。。。
}
}
其实到这里,咱们再串联上个小部分的代码,应该就能看出一些端倪,上述代码总结:
internal static class ServerServiceDefinitionExtensions
{
//在写服务端的时候,我们需要绑定服务,而在绑定服务的时候需要先调用静态BindService方法(可以在proto生成的代码中看到这个方法),然后添加Services时,内部会调用GetCallHandlers方法。
internal static ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers(this ServerServiceDefinition serviceDefinition)
{
//构建默认的ServiceBinder,里面其实是执行构造的最终handler
var binder = new DefaultServiceBinder();
//调用BindService方法,将执行集合委托
serviceDefinition.BindService(binder);
//返回集合列表
return binder.GetCallHandlers();
}
private class DefaultServiceBinder : ServiceBinderBase
{
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
internal ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers()
{
return new ReadOnlyDictionary<string, IServerCallHandler>(this.callHandlers);
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
{
//每个方法名称对应的一个handler
callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
}
}
}
上述代码总结:
关于Grpc的拦截器,相信你看完之后会有一定的收获,这里我再额外说一些其他的关于阅读Grpc源码时的小tips:
以上就是笔者对Grpc拦截器的理解,本篇文章也主要是希望给读者提供源码阅读思路,可能会有偏差,还请评论指正😂。
以上是脚本宝典为你收集整理的源码解析Grpc拦截器(C#版本)全部内容,希望文章能够帮你解决源码解析Grpc拦截器(C#版本)所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。