gRPC Client Middleware.
中间件想必大家不陌生,今天给大家介绍如何实现中间件以及实现gRPC的客户端中间件。
什么是中间件?
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/index?view=aspnetcore-2.1&tabs=aspnetcore2x
中间件管道
先定义管道Pipeline
/// <summary>
/// Built pipeline for gRPC
/// </summary>
public class Pipeline
{
private PipelineDelagate processChain; internal Pipeline(PipelineDelagate middlewareChain)
{
processChain = middlewareChain;
} internal Task RunPipeline(MiddlewareContext context)
{
return processChain(context);
}
}
然后实现PipelineBuilder
/// <summary>
/// PipelineBuilder
/// </summary>
public class PipelineBuilder
{
private List<Func<PipelineDelagate, PipelineDelagate>> middlewares = new List<Func<PipelineDelagate, PipelineDelagate>>(); /// <summary>
/// Add a middleware
/// </summary>
public PipelineBuilder Use(Func<PipelineDelagate, PipelineDelagate> middleware)
{
middlewares.Add(middleware);
return this;
} /// <summary>
/// Use
/// </summary>
public PipelineBuilder Use<T>(params object[] args)
{
middlewares.Add(d => WrapClass<T>(d, args));
return this;
} /// <summary>
/// UseWhen
/// </summary>
public PipelineBuilder UseWhen<T>(Func<MiddlewareContext, bool> condition, params object[] args)
{
middlewares.Add(d =>
{
return async ctx => { if (condition(ctx)) { await WrapClass<T>(d, args)(ctx); } };
});
return this;
} /// <summary>
/// Use
/// </summary>
public PipelineBuilder Use(Func<MiddlewareContext, PipelineDelagate, Task> middleware)
{
middlewares.Add(d =>
{
return ctx => { return middleware(ctx, d); };
});
return this;
} private PipelineDelagate WrapClass<T>(PipelineDelagate next, params object[] args)
{
var ctorArgs = new object[args.Length + 1];
ctorArgs[0] = next;
Array.Copy(args, 0, ctorArgs, 1, args.Length);
var type = typeof(T);
var instance = Activator.CreateInstance(type, ctorArgs);
MethodInfo method = type.GetMethod("Invoke");
return (PipelineDelagate)method.CreateDelegate(typeof(PipelineDelagate), instance);
} /// <summary>
/// Build
/// </summary>
public Pipeline Build()
{
PipelineDelagate pipeline = ExecuteMainHandler;
middlewares.Reverse();
foreach (var middleware in middlewares)
{
pipeline = middleware(pipeline);
}
return new Pipeline(pipeline);
} internal static Task ExecuteMainHandler(MiddlewareContext context)
{
return context.HandlerExecutor();
}
}
MiddlewareContext 和 委托定义
/// <summary>
/// MiddlewareContext
/// </summary>
public class MiddlewareContext
{
public IMethod Method { get; set; } public object Request { get; set; } public object Response { get; set; } public string Host { get; set; } public CallOptions Options { get; set; } internal Func<Task> HandlerExecutor { get; set; }
} public delegate Task PipelineDelagate(MiddlewareContext context);
到这里管道建设完成,那个如何在gRPC中使用呢?
首先实现自己的客户端拦截器MiddlewareCallInvoker
public sealed class MiddlewareCallInvoker : DefaultCallInvoker
{
private readonly Channel grpcChannel; private Pipeline MiddlewarePipeline { get; set; } public MiddlewareCallInvoker(Channel channel) : base(channel)
{
this.grpcChannel = channel;
} public MiddlewareCallInvoker(Channel channel, Pipeline pipeline) : this(channel)
{
this.MiddlewarePipeline = pipeline;
} private TResponse Call<TResponse>(Func<MiddlewareContext, TResponse> call, MiddlewareContext context)
{ TResponse response = default(TResponse);
if (MiddlewarePipeline != null)
{
context.HandlerExecutor = async () =>
{
response = await Task.FromResult(call(context));
context.Response = response;
};
MiddlewarePipeline.RunPipeline(context).ConfigureAwait(false);
}
else
{
response = call(context);
}
return response; } public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method,
string host, CallOptions options, TRequest request)
{
return Call((context) => base.BlockingUnaryCall((Method<TRequest, TResponse>)context.Method, context.Host, context.Options, (TRequest)context.Request), new MiddlewareContext
{
Host = host,
Method = method,
Options = options,
Request = request,
Response = null
});
} public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
{
return Call((context) => base.AsyncUnaryCall((Method<TRequest, TResponse>)context.Method, context.Host, context.Options, (TRequest)context.Request), new MiddlewareContext
{
Host = host,
Method = method,
Options = options,
Request = request,
Response = null
});
} public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options,
TRequest request)
{
return Call((context) => base.AsyncServerStreamingCall((Method<TRequest, TResponse>)context.Method, context.Host, context.Options, (TRequest)context.Request), new MiddlewareContext
{
Host = host,
Method = method,
Options = options,
Request = request,
Response = null
});
} public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
{
return Call((context) => base.AsyncClientStreamingCall((Method<TRequest, TResponse>)context.Method, context.Host, context.Options), new MiddlewareContext
{
Host = host,
Method = method,
Options = options,
Request = null,
Response = null
});
} public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
{
return Call((context) => base.AsyncDuplexStreamingCall((Method<TRequest, TResponse>)context.Method, context.Host, context.Options), new MiddlewareContext
{
Host = host,
Method = method,
Options = options,
Request = null,
Response = null
});
}
}
到这里基于管道的中间件基本完成。接下来就是在客户端使用了
var pipeline = new PipelineBuilder()
//.Use<ExceptionMiddleware>()
//.Use<TimerMiddleware>()
//.Use<LoggingMiddleware>()
//.Use<TimeoutMiddleware>()
.Use<PolicyMiddleware>(new PolicyMiddlewareOptions
{
RetryTimes = 2,
TimoutMilliseconds = 100
})
;
//pipeline.Use<LoggingMiddleware>();// pipeline.UseWhen<LoggingMiddleware>(ctx => ctx.Context.Method.EndsWith("SayHello"));
//pipeline.Use<TimeoutMiddleware>(new TimeoutMiddlewareOptions { TimoutMilliseconds = 1000 });
//console logger
pipeline.Use(async (ctx, next) =>
{
Console.WriteLine(ctx.Request.ToString());
await next(ctx);
Console.WriteLine(ctx.Response.ToString());
}); Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
MiddlewareCallInvoker callInvoker = new MiddlewareCallInvoker(channel, pipeline.Build()); var clientApi = new Get.GetClient(callInvoker); var replyApi = clientApi.SayHello(new ContractsSample1.HelloApiDemo.HelloRequest { Name = " APII" });
Console.WriteLine("Greeting: " + replyApi.Message);
Middleware
public class LoggingMiddleware
{
private PipelineDelagate _next; public LoggingMiddleware(PipelineDelagate next)
{
_next = next;
} public async Task Invoke(MiddlewareContext context)
{
//Before
await _next(context);
//End
}
}
至此已完成所有工作。希望能够帮助到大家。
如果有机会将给大家介绍gRPC跨平台网关,该网关能够实现自动将下游的gRPC服务转化成http api,只需要你的proto文件即可。如果你使用consul,甚至无需你做任务配置。
gRPC Client Middleware.的更多相关文章
- gRPC Client的负载均衡器
一.gRPC是什么? gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协 ...
- Building gRPC Client iOS Swift Note Taking App
gRPC is an universal remote procedure call framework developed by Google that has been gaining inter ...
- yoyogo v1.7.4 发布,支持 grpc v1.3.8 & etcd 3.5.0
YoyoGo (Go语言框架)一个简单.轻量.快速.基于依赖注入的微服务框架( web .grpc ),支持Nacos/Consoul/Etcd/Eureka/k8s /Apollo等 . https ...
- gRPC源码分析1-SSL/TLS
引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...
- gRPC .NET Core跨平台学习
前些天发布gRPC C# 学习,在.NET Framework 中使用gRPC ,今天来学习 .NET Core gRPC. gRPC 的.NET Core 包在NuGet 上发布了,结合.NET C ...
- gRPC helloworld service, RESTful JSON API gateway and swagger UI
概述 本篇博文完整讲述了如果通过 protocol buffers 定义并启动一个 gRPC 服务,然后在 gRPC 服务上提供一个 RESTful JSON API 的反向代理 gateway,最后 ...
- 开始食用grpc(之一)
开始食用grpc(之一) 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9501353.html ``` 记一次和一锅们压马路,路过一咖啡厅(某巴克),随口 ...
- gRPC 在 Python中的应用
python -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. hello.proto 简介 在python ...
- Abp + gRpc 如何实现用户会话状态传递
0.背景 在实际项目当中,我们采用的是 Abp 框架,但是 Abp 框架官方并没有针对 Grpc 进行模块封装.基于此我结合 Abp 与 MagicOnion 封装了一个 Abp.Grpc 模块,它包 ...
随机推荐
- pandas(二)
层级索引: index=[('a',2010),('b',2011),('c',2010'),('a',2012),('e',2010),('f',2011)] age=[18,17,18,16,18 ...
- numpy(三)
广播: x= np.arange(12).reshape((3,4)) a= np.arange(3) b=np.arange(3)[;,np.newaxis] c=a+b a,b会扩散成公共的形状进 ...
- linux 对MTD分区nand flash的烧写和读取
使用mtd-utils工具实现对flash的升级分区的烧写yaffs2 yaffs2的格式是根据所使用的nandflash来制作的,不同的nandflash,得到的yaffs2是不一样的,具体可以参考 ...
- Mysql笔试题
1.查询Student表中的所有记录的Sname.Ssex和Class列. SELECT Sname,Ssex,Class FROM Students; 2.查询教师所有的单位即不重复的Depart列 ...
- 从合并两个Map说开去 - foldLeft 和 foldRight 还有模式匹配
开发中遇到需求:合并两个Map集合对象(将两个对应Key的值累加) 先说解决方案: ( map1 /: map2 ) { )) ) } 首先: Scala中现有的合并集合操作不能满足这个需求 . 注意 ...
- 深入理解Java虚拟机8-chap12-13-斗者5星
一.操作系统与内存 通过在处理器与内存之间添加一层访问及更新速度更快的高速缓存,可以一定程度解决处理器与内存速度的矛盾 引入新问题:缓存一致性,即每个处理器只与自己的缓存交互,如果操作的是内存中的同一 ...
- python --(链表)
链表的使用 #/usr/bin/python#-*- coding: utf-8 -*-#Function: simulate the link-list in python#__author__: ...
- 获取Type的三种方式
using System;using UnityEngine; public class Type_Test : MonoBehaviour{ private void Awake() { ...
- 纯JS.CSS编写的可拖拽并左右分栏的插件(复制代码就能用)
<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equ ...
- Dynamics CRM On-Premise V9安装手记
下载地址: https://download.microsoft.com/download/A/D/D/ADDD6898-4EFA-46FA-80B6-6FE9A3CDED63/CRM9.0-Serv ...