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 模块,它包 ...
随机推荐
- opencart3产品页调用upc/数量等信息
opencart3产品页默认只调用标题.价格.型号等几个数据,如果想要调用更多的参数要如何操作呢?跟着ytkah一起来看看吧.首先打开/catalog/model/catalog/product.ph ...
- 2018-2019-2 20165236郭金涛《网络对抗》Exp1 PC平台逆向破解
2018-2019-2 20165236郭金涛<网络对抗>Exp1 PC平台逆向破解 一.实验内容 1.掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码(0.5分) 2.掌 ...
- ELK日志分析解决方案
概要 ELK(Elasticsearch , Logstash, Kibana的简称)是目前比较流行的日志分析解决方案,核心包括了三个部分 Elasticsearch:日志查询分析引擎 Logstas ...
- egg.js异步请求数据
之前已经简单的使用egg-init初始化项目,并创建控制器controller和服务service 在实际项目中, service主要负责数据的请求,并处理(http请求) controll主要负责获 ...
- 北京大学Cousera学习笔记--7-计算导论与C语言基础--基本数据类型&变量&常量
1.整形数据 1.基本型(int 4B).短整型(short 2B).长整型(long 4B) VC环境下 sizeof运算符用于计算某种类型的对象在内存中所占的字节数 ,用法:size(int) ...
- spring boot 整合 百度ueditor富文本
百度的富文本没有提供Java版本的,只给提供了jsp版本,但是呢spring boot 如果是使用内置tomcat启动的话整合jsp是非常困难得,今天小编给大家带来spring boot整合百度富文本 ...
- python数据类型值数字类型
1.bin()函数是将十进制数转换成二进制数 2.oct()函数将十进制数转换成八进制数 3.hex()函数将十进制数转换成十六进制 数 十六进制表示:0-9 a b c d e f 4.数字 ...
- C# Window Service安装、卸载、恢复选项操作
using System;using System.Diagnostics;using System.Linq;using System.ServiceProcess; namespace ScmWr ...
- Running ROS on Windows 10
1.在Windows10下安装ROS.需要开启WSL.参考 2.修改ubuntu国内源,可以提高安装包下载更新速度. (1)原文件备份:sudo cp /etc/apt/sources.list /e ...
- Excel坐标自动在AutoCad绘图_5
众所周知,Excel对数据处理的功能非常强大,它可以进行数据处理.统计分析已经辅助决策的操作,该软件已经渗透到各个领域.作为一个测绘人,GISer, 也经常利用excel完成一些测量表格的自动化计算, ...