今天给大家介绍一下基于.NetCore的RPC框架DotNetCoreRpc都是怎样的。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。
前言
一直以来对内部服务间使用RPC的方式调用都比较赞同,因为内部间没有这么多限制,最简单明了的方式就是最合适的方式。个人比较喜欢类似Dubbo的那种使用方式,采用和本地方法相同的方式,把接口层独立出来作为服务契约,为服务端提供服务,客户端也通过此契约调用服务。.Net平台上类似Dubbo这种相对比较完善的RPC框架还是比较少的,GRPC确实是一款非常优秀的RPC框架,能跨语言调用,但是每次还得编写proto文件,个人感觉还是比较麻烦的。如今服务拆分,微服务架构比较盛行的潮流下,一个简单实用的RPC框架确实可以提升很多开发效率。
简介
随着.Net Core逐渐成熟稳定,为我一直以来想实现的这个目标提供了便利的方式。于是利用闲暇时间本人手写了一套基于Asp.Net Core的RPC框架,算是实现了一个自己的小目标。大致的实现方式,Server端依赖Asp.Net Core,采用的是中间件的方式拦截处理请求比较方便。Client端可以是任何可承载.Net Core的宿主程序。通信方式是HTTP协议,使用的是HttpClientFactory。至于为什么使用HttpClientFactory,因为HttpClientFactory可以更轻松的实现服务发现,而且可以很好的集成Polly,很方便的实现,超时重试,熔断降级这些,给开发过程中提供了很多便利。由于本人能力有限,基于这些便利,站在巨人的肩膀上,简单的实现了一个RPC框架,项目托管在GitHub上https://github.com/softlgl/DotNetCoreRpc有兴趣的可以自行查阅。
开发环境
Visual Studio 2019
.Net Standard 2.1
Asp.Net Core 3.1.x
使用方式
打开Visual Studio先新建一个RPC契约接口层,这里我起的名字叫IRpcService。然后新建一个Client层(可以是任何可承载.Net Core的宿主程序)叫ClientDemo,然后建立一个Server层(必须是Asp.Net Core项目)叫WebDemo,文末附本文Demo连接,建完这些之后项目结构如下:
Client端配置#
Client端引入DotNetCoreRpc.Client包,并引入自定义的契约接口层
<PackageReferenceInclude="DotNetCoreRpc.Client">
然后可以愉快的编码了,大致编码如下
classProgram { staticvoidMain(string[]args) { IServiceCollectionservices=newServiceCollection(); //*注册DotNetCoreRpcClient核心服务 services.AddDotNetCoreRpcClient() //*通信是基于HTTP的,内部使用的HttpClientFactory,自行注册即可 .AddHttpClient("WebDemo",client=>{client.BaseAddress=newUri("http://localhost:13285/");}); IServiceProviderserviceProvider=services.BuildServiceProvider(); //*获取RpcClient使用这个类创建具体服务代理对象 RpcClientrpcClient=serviceProvider.GetRequiredService<RpcClient>(); //IPersonService是我引入的服务包interface,需要提供ServiceName,即AddHttpClient的名称 IPersonServicepersonService=rpcClient.CreateClient<IPersonService>("WebDemo"); PersonDtopersonDto=newPersonDto { Id=1, Name="yi念之间", Address="中国", BirthDay=newDateTime(2000,12,12), IsMarried=true, Tel=88888888888 }; booladdFlag=personService.Add(personDto); Console.WriteLine($"添加结果=[{addFlag}]"); varperson=personService.Get(personDto.Id); Console.WriteLine($"获取person结果=[{person.ToJson()}]"); varpersons=personService.GetAll(); Console.WriteLine($"获取persons结果=[{persons.ToList().ToJson()}]"); personService.Delete(person.Id); Console.WriteLine($"删除完成"); Console.ReadLine(); } }
到这里Client端的代码就编写完成了
Server端配置#
Client端引入DotNetCoreRpc.Client包,并引入自定义的契约接口层
<PackageReferenceInclude="DotNetCoreRpc.Server"Version="1.0.2"/>
然后编写契约接口实现类,比如我的叫PersonService
//实现契约接口IPersonService publicclassPersonService:IPersonService { privatereadonlyConcurrentDictionary<int,PersonDto>persons=newConcurrentDictionary<int,PersonDto>(); publicboolAdd(PersonDtoperson) { returnpersons.TryAdd(person.Id,person); } publicvoidDelete(intid) { persons.Remove(id,outPersonDtoperson); } //自定义Filter [CacheFilter(CacheTime=500)] publicPersonDtoGet(intid) { returnpersons.GetValueOrDefault(id); } //自定义Filter [CacheFilter(CacheTime=300)] publicIEnumerable<PersonDto>GetAll() { foreach(variteminpersons) { yieldreturnitem.Value; } } }
通过上面的代码可以看出,我自定义了Filter,这里的Filter并非Asp.Net Core框架定义的Filter,而是DotNetCoreRpc框架定义的Filter,自定义Filter的方式如下
//*要继承自抽象类RpcFilterAttribute publicclassCacheFilterAttribute:RpcFilterAttribute { publicintCacheTime{get;set;} //*支持属性注入,可以是public或者private //*这里的FromServices并非Asp.NetCore命名空间下的,而是来自DotNetCoreRpc.Core命名空间 [FromServices] privateRedisConfigOptionsRedisConfig{get;set;} [FromServices] publicILogger<CacheFilterAttribute>Logger{get;set;} publicoverrideasyncTaskInvokeAsync(RpcContextcontext,RpcRequestDelegatenext) { Logger.LogInformation($"CacheFilterAttributeBegin,CacheTime=[{CacheTime}],Class=[{context.TargetType.FullName}],Method=[{context.Method.Name}],Params=[{JsonConvert.SerializeObject(context.Parameters)}]"); awaitnext(context); Logger.LogInformation($"CacheFilterAttributeEnd,ReturnValue=[{JsonConvert.SerializeObject(context.ReturnValue)}]"); } }
以上代码基本上完成了对服务端业务代码的操作,接下来我们来看如何在Asp.Net Core中配置使用DotNetCoreRpc。打开Startup,配置如下代码既可
publicclassStartup { publicvoidConfigureServices(IServiceCollectionservices) { services.AddSingleton<IPersonService,PersonService>() .AddSingleton(newRedisConfigOptions{Address="127.0.0.1:6379",Db=10}) //*注册DotNetCoreRpcServer .AddDotNetCoreRpcServer(options=>{ //*确保添加的契约服务接口事先已经被注册到DI容器中 //添加契约接口 //options.AddService<IPersonService>(); //或添加契约接口名称以xxx为结尾的 //options.AddService("*Service"); //或添加具体名称为xxx的契约接口 //options.AddService("IPersonService"); //或扫描具体命名空间下的契约接口 options.AddNameSpace("IRpcService"); //可以添加全局过滤器,实现方式和CacheFilterAttribute一致 options.AddFilter<LoggerFilterAttribute>(); }); } publicvoidConfigure(IApplicationBuilderapp,IWebHostEnvironmentenv) { //这一堆可以不要+1 if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //添加DotNetCoreRpc中间件既可 app.UseDotNetCoreRpc(); //这一堆可以不要+2 app.UseRouting(); //这一堆可以不要+3 app.UseEndpoints(endpoints=> { endpoints.MapGet("/",asynccontext=> { awaitcontext.Response.WriteAsync("ServerStart!"); }); }); } }
DotNetCoreRpc都是怎样的相关的内容可以搜索恒创之前的文章或者浏览下面的文章进行学习哈!相信小编会给大家增添更多知识,希望大家能够支持一下恒创!