GRPC 是谷歌发布的一个开源、高性能、通用RPC服务,尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2。还有就是它具有跨平台、跨语言 等特性,这里就不再说明RPC是啥。

  在写项目当中,grp服务过多会非常头疼,那么我们分析一下如果解决这个问题。我们都知道在grpc注入到.NET Core 中使用的方法是 MapGrpcService 方法,是一个泛型方法。

    [NullableAttribute()]
[NullableContextAttribute()]
public static class GrpcEndpointRouteBuilderExtensions
{
public static GrpcServiceEndpointConventionBuilder MapGrpcService<TService>(this IEndpointRouteBuilder builder) where TService : class;
}

那我们就可以通过反射调用这个方法来进行服务批量注册,看方法的样子我们只需要将我们的服务对应 TService 以及将我们的 endpointBuilder 传入即可,我们看下源码是不是就像我所说的那样?

    public static class GrpcEndpointRouteBuilderExtensions
{
public static GrpcServiceEndpointConventionBuilder MapGrpcService<TService>(this IEndpointRouteBuilder builder) where TService : class
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
} ValidateServicesRegistered(builder.ServiceProvider); var serviceRouteBuilder = builder.ServiceProvider.GetRequiredService<ServiceRouteBuilder<TService>>();
var endpointConventionBuilders = serviceRouteBuilder.Build(builder); return new GrpcServiceEndpointConventionBuilder(endpointConventionBuilders);
} private static void ValidateServicesRegistered(IServiceProvider serviceProvider)
{
var marker = serviceProvider.GetService(typeof(GrpcMarkerService));
if (marker == null)
{
throw new InvalidOperationException("Unable to find the required services. Please add all the required services by calling " +
"'IServiceCollection.AddGrpc' inside the call to 'ConfigureServices(...)' in the application startup code.");
}
}
}

  ok,看样子没什么问题就像我刚才所说的那样做。现在我们准备一个proto以及一个Service.这个就在网上找个吧..首先定义一个proto,它是grpc中的协议,也就是每个消费者遵循的。

syntax = "proto3";
option csharp_namespace = "Grpc.Server";
package Greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = ;
enum Laguage{
en_us = ;
zh_cn = ;
}
Laguage LaguageEnum = ;
}
message HelloReply {
string message = ;
int32 num = ;
int32 adsa =;
}

随后定义Service,当然非常简单, Greeter.GreeterBase 是重新生成项目根据proto来生成的。

public class GreeterService : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
var greeting = string.Empty;
switch (request.LaguageEnum)
{
case HelloRequest.Types.Laguage.EnUs:
greeting = "Hello";
break;
case HelloRequest.Types.Laguage.ZhCn:
greeting = "你好";
break;
}
return Task.FromResult(new HelloReply
{
Message = $"{greeting} {request.Name}",
Num = new Random().Next()
});
}
}

此时我们需要自定义一个中间件,来批量注入grpc服务,其中我们获取了类型为 GrpcEndpointRouteBuilderExtensions ,并获取了它的方法,随后传入了他的TService,最后通过Invoke转入了我们的终点对象。

public static class GrpcServiceExtension
{
public static void Add_Grpc_Services(IEndpointRouteBuilder builder)
{
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (var item in ServicesHelper.GetGrpcServices("Grpc.Server"))
{
Type mytype = assembly.GetType(item.Value + "."+item.Key);
var method = typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService").MakeGenericMethod(mytype);
method.Invoke(null, new[] { builder });
};
}
public static void useMyGrpcServices(this IApplicationBuilder app)
{
app.UseEndpoints(endpoints =>
{
Add_Grpc_Services(endpoints);
});
}
}

在 ServicesHelper 中通过反射找到程序集当中的所有文件然后判断并返回。

 public static class ServicesHelper
{
public static Dictionary<string,string> GetGrpcServices(string assemblyName)
{
if (!string.IsNullOrEmpty(assemblyName))
{
Assembly assembly = Assembly.Load(assemblyName);
List<Type> ts = assembly.GetTypes().ToList(); var result = new Dictionary<string, string>();
foreach (var item in ts.Where(u=>u.Namespace == "Grpc.Server.Services"))
{
result.Add(item.Name,item.Namespace);
}
return result;
}
return new Dictionary<string, string>();
}
}

这样子我们就注入了所有命名空间为Grpc.Server.Services的服务,但这样好像无法达到某些控制,我们应当如何处理呢,我建议携程Attribute的形式,创建一个Flag.

public class GrpcServiceAttribute : Attribute
{
public bool IsStart { get; set; }
}

将要在注入的服务商添加该标识,例如这样。

 [GrpcService]
public class GreeterService : Greeter.GreeterBase
{...}

随后根据反射出来的值找到 AttributeType 的名称进行判断即可。

 public static Dictionary<string,string> GetGrpcServices(string assemblyName)
{
if (!string.IsNullOrEmpty(assemblyName))
{
Assembly assembly = Assembly.Load(assemblyName);
List<Type> ts = assembly.GetTypes().ToList(); var result = new Dictionary<string, string>();
foreach (var item in ts.Where(u=>u.CustomAttributes.Any(a=>a.AttributeType.Name == "GrpcServiceAttribute")))
{
result.Add(item.Name,item.Namespace);
}
return result;
}
return new Dictionary<string, string>();
}

随后我们的批量注入在Starup.cs中添加一行代码即可。

app.useMyGrpcServices();

启动项目试一试效果:

示例代码:传送门

在.NET Core中批量注入Grpc服务的更多相关文章

  1. 如何在 asp.net core 3.x 的 startup.cs 文件中获取注入的服务

    一.前言 从 18 年开始接触 .NET Core 开始,在私底下.工作中也开始慢慢从传统的 mvc 前后端一把梭,开始转向 web api + vue,之前自己有个半成品的 asp.net core ...

  2. .Net Core中依赖注入服务使用总结

    一.依赖注入 引入依赖注入的目的是为了解耦和.说白了就是面向接口编程,通过调用接口的方法,而不直接实例化对象去调用.这样做的好处就是如果添加了另一个种实现类,不需要修改之前代码,只需要修改注入的地方将 ...

  3. (2)ASP.NET Core 依赖关系注入(服务)

    1.前言 面向对象设计(OOD)里有一个重要的思想就是依赖倒置原则(DIP),并由该原则牵引出依赖注入(DI).控制反转(IOC)及其容器等老生常谈的概念,初学者很容易被这些概念搞晕(包括我在内),在 ...

  4. .NET Core 中依赖注入框架详解 Autofac

    本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的 Autofac相比.NET Core原生的注入方式提供了强大的功能, ...

  5. 用工厂模式解决ASP.NET Core中依赖注入的一个烦恼

    这是最近在实际开发中遇到的一个问题,用 asp.net core 开发一个后端 web api ,根据指定的 key 清除 2 台 memcached 服务器上的缓存.背景是我们在进行 .net co ...

  6. .NET Core 中依赖注入 AutoMapper 小记

    最近在 review 代码时发现同事没有像其他项目那样使用 AutoMapper.Mapper.Initialize() 静态方法配置映射,而是使用了依赖注入 IMapper 接口的方式 servic ...

  7. ASP.NET Core开发-获取所有注入(DI)服务

    获取ASP.NET Core中所有注入(DI)服务,在ASP.NET Core中加入了Dependency Injection依赖注入. 我们在Controller,或者在ASP.NET Core程序 ...

  8. NET Core开发-获取所有注入(DI)服务

    NET Core开发-获取所有注入(DI)服务 获取ASP.NET Core中所有注入(DI)服务,在ASP.NET Core中加入了Dependency Injection依赖注入. 我们在Cont ...

  9. ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)

    早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...

随机推荐

  1. H3C 错误提示信息

  2. Laravel 修改默认日志文件名称和位置

    修改默认日志位置 我们平常的开发中可能一直把laravel的日志文件放在默认位置不会有什么影响,但如果我们的项目上线时是全量部署,每次部署都是git中最新的代码,那这个时候每次都会清空我们的日志,显示 ...

  3. meta标签、常用的文字类标签及其区别

    常用的文字类基本标签 段落:p标题文字 :h1~h6超链接:a,必须属性href,后跟跳转地址图片:img,必须属性src,后跟图片地址字体斜体:em.i 文字加粗:b.strong文字下划线:u文字 ...

  4. BraveOS正式版发布,希望大家下载使用

    废话不多说,直接贴图才是王道 这里是DOS系统+默认官方(Platform系统) 下载地址:http://pan.baidu.com/s/1eQINwx8 (引导进Platform系统后,默认管理员帐 ...

  5. Attention is all your need 谷歌的超强特征提取网络——Transformer

    过年放了七天假,每年第一件事就是立一个flag——希望今年除了能够将技术学扎实之外,还希望能够将所学能够用来造福社会,好像flag立得有点大了.没关系,套用一句电影台词为自己开脱一下——人没有梦想,和 ...

  6. landi pos机

    2015年3月:联迪商用获得2014-2015中国金融POS机市场年度成功企业奖: 2014年5月:联迪商用入选2013年福州市纳税百强企业: 2013年12月:联迪商用入选2013年度中国电子商务物 ...

  7. Python--day45--pymysql操作数据库详细

    1.一个pymysql往数据库提交数据的简单例子: import pymysql # user = "eric" # pwd = '123123' #增加 conn = pymys ...

  8. 安装 Sureface Hub 系统 Windows 10 team PPIPro 系统

    本文告诉大家如何安装这个系统 本文的方法我自己没试过,如果失败了,不要打我 下载地址 中文版 https://pan.baidu.com/s/1gAJSSE6KB9JHXo4BT_VfmA 其他请看 ...

  9. Server,Servlet,ServletConfig,ServletContext,Session,Request,Response

    Server流程 解析URL->找到应用->找到Servlet->实例化Servlet->调用init->调用service->返回响应->调用destroy ...

  10. Educational Codeforces Round 54 (Rated for Div. 2) D Edge Deletion (SPFA + bfs)

    题目大意:给定你一个包含n个点m条边的无向图,现在最多在图中保留k条边,问怎么删除多的边,使得图中良好的节点数最多,求出保留在图中的边的数量和编号. 良好的节点定义为:删除某条边后该点到点1的最短距离 ...