中间件想必大家不陌生,今天给大家介绍如何实现中间件以及实现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.的更多相关文章

  1. gRPC Client的负载均衡器

    一.gRPC是什么? gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协 ...

  2. Building gRPC Client iOS Swift Note Taking App

    gRPC is an universal remote procedure call framework developed by Google that has been gaining inter ...

  3. yoyogo v1.7.4 发布,支持 grpc v1.3.8 & etcd 3.5.0

    YoyoGo (Go语言框架)一个简单.轻量.快速.基于依赖注入的微服务框架( web .grpc ),支持Nacos/Consoul/Etcd/Eureka/k8s /Apollo等 . https ...

  4. gRPC源码分析1-SSL/TLS

    引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...

  5. gRPC .NET Core跨平台学习

    前些天发布gRPC C# 学习,在.NET Framework 中使用gRPC ,今天来学习 .NET Core gRPC. gRPC 的.NET Core 包在NuGet 上发布了,结合.NET C ...

  6. gRPC helloworld service, RESTful JSON API gateway and swagger UI

    概述 本篇博文完整讲述了如果通过 protocol buffers 定义并启动一个 gRPC 服务,然后在 gRPC 服务上提供一个 RESTful JSON API 的反向代理 gateway,最后 ...

  7. 开始食用grpc(之一)

    开始食用grpc(之一) 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9501353.html ```   记一次和一锅们压马路,路过一咖啡厅(某巴克),随口 ...

  8. gRPC 在 Python中的应用

    python -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. hello.proto 简介 在python ...

  9. Abp + gRpc 如何实现用户会话状态传递

    0.背景 在实际项目当中,我们采用的是 Abp 框架,但是 Abp 框架官方并没有针对 Grpc 进行模块封装.基于此我结合 Abp 与 MagicOnion 封装了一个 Abp.Grpc 模块,它包 ...

随机推荐

  1. 使用@Autowired时,取值为null

    如果取不到,可以考虑其他方式 场景: @Autowired private StringRedisTemplate redisTemplate; 想使用redisTemplate,但是使用时为null ...

  2. ajax阻挡设置

    在请求时候设置一个变量为false的.请求方法时候用他的值判断是否在请求中,如果是true就是有请求了,就直接return ,不执行后面的方法, 如果是没有请求,就让值为true,然后开始执行ajax ...

  3. (转)测试如何区别是前端的问题还是后台的bug

    常常说到的一个IT项目,包括前端开发,后台开发,软件测试,架构,项目经理,产品需求.那么对于一位优秀的软件测试工程师来说,需要区分前端和后台的工作就显得尤为重要. - 什么是前端和后台 简而言之,前端 ...

  4. arcgis for JavaScript API 4.5与4.3的区别

    arcgis 4.5与4.3区别: 鉴于本人使用4.3时间比较久,而arcgis for JavaScript API于9月28日推出了4.5版本,但是直接更换4.5的init.js会出现意想不到的错 ...

  5. laravel中get()与 first()区别、collection与stdClass的区别

    简单的,laravel里get()得到的是一组数据,first()得到的是一个model数据. 从形式上,laravel里每一个model数据(record),在取出的时候都是用的PHP的stdCla ...

  6. 2019春下载的sublime text都无法自动安装package control:解决办法

    之前电脑的原因卸载了,于是重新安装sublime text3. 发现问题了.Package Control无法自动安装. 于是一通常用操作. 1.copy 安装码(你知道的)到control安装,失败 ...

  7. python学习笔记之socket(第七天)

         参考文档:              1.金角大王博客:http://www.cnblogs.com/alex3714/articles/5227251.html               ...

  8. IO流(一)

    一.异常 概述 异常就是Java程序在运行过程中出现的错误. 由来 问题也是现实生活中一个具体事务,也可以通过java的类的形式进行描述,并封装成对象.其实就是Java对不正常情况进行描述后的对象体现 ...

  9. angular4 使用swiper 首次加载问题(一)

    angular 在使用外部插件swiper 还是有不少小坑的,下面来聊一聊.angular在使用swiper 的一些坑 一开始觉得使用外部引入的方式比较好,就在外部定义了.简单快捷方便, 但是在开发后 ...

  10. 手把手教你如何安装Pycharm

    手把手教你如何安装Pycharm——靠谱的Pycharm安装详细教程     今天小编给大家分享如何在本机上下载和安装Pycharm,具体的教程如下: 1.首先去Pycharm官网,或者直接输入网址: ...