├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── Rpc.sln └── src ├── Rabbit.Rpc.ProxyGenerator ├── IServiceProxyFactory.cs ├── IServiceProxyGenerater.cs ├── Implementation │ ├── ServiceProxyBase.cs │ ├── ServiceProxyFactory.cs │ └── ServiceProxyGenerater.cs ├── Properties │ └── AssemblyInfo.cs ├── Rabbit.Rpc.ProxyGenerator.csproj ├── RpcServiceCollectionExtensions.cs └── Utilitys │ └── CompilationUtilitys.cs ├── Rabbit.Rpc ├── Address │ ├── AddressModel.cs │ └── IpAddressModel.cs ├── Convertibles │ ├── ITypeConvertibleProvider.cs │ ├── ITypeConvertibleService.cs │ └── Implementation │ │ ├── DefaultTypeConvertibleProvider.cs │ │ └── DefaultTypeConvertibleService.cs ├── Exceptions │ ├── RpcCommunicationException.cs │ ├── RpcException.cs │ └── RpcRemoteException.cs ├── Ids │ ├── IServiceIdGenerator.cs │ └── Implementation │ │ └── DefaultServiceIdGenerator.cs ├── Logging │ ├── ConsoleLogger.cs │ ├── ILogger.cs │ └── NullLogger.cs ├── Messages │ ├── RemoteInvokeMessage.cs │ ├── RemoteInvokeResultMessage.cs │ └── TransportMessage.cs ├── Properties │ └── AssemblyInfo.cs ├── Rabbit.Rpc.csproj ├── Routing │ ├── IServiceRouteFactory.cs │ ├── IServiceRouteManager.cs │ ├── Implementation │ │ ├── DefaultServiceRouteFactory.cs │ │ ├── ServiceRouteManagerBase.cs │ │ └── SharedFileServiceRouteManager.cs │ ├── ServiceRoute.cs │ └── ServiceRouteDescriptor.cs ├── RpcServiceCollectionExtensions.cs ├── Runtime │ ├── Client │ │ ├── Address │ │ │ └── Resolvers │ │ │ │ ├── IAddressResolver.cs │ │ │ │ └── Implementation │ │ │ │ ├── DefaultAddressResolver.cs │ │ │ │ └── Selectors │ │ │ │ ├── IAddressSelector.cs │ │ │ │ └── Implementation │ │ │ │ ├── AddressSelectorBase.cs │ │ │ │ ├── PollingAddressSelector.cs │ │ │ │ └── RandomAddressSelector.cs │ │ ├── HealthChecks │ │ │ ├── IHealthCheckService.cs │ │ │ └── Implementation │ │ │ │ └── DefaultHealthCheckService.cs │ │ ├── IRemoteInvokeService.cs │ │ ├── Implementation │ │ │ └── RemoteInvokeService.cs │ │ └── RemoteInvokeContext.cs │ └── Server │ │ ├── IServiceEntryLocate.cs │ │ ├── IServiceEntryManager.cs │ │ ├── IServiceEntryProvider.cs │ │ ├── IServiceExecutor.cs │ │ ├── IServiceHost.cs │ │ ├── Implementation │ │ ├── DefaultServiceEntryLocate.cs │ │ ├── DefaultServiceEntryManager.cs │ │ ├── DefaultServiceExecutor.cs │ │ ├── DefaultServiceHost.cs │ │ ├── ServiceDiscovery │ │ │ ├── Attributes │ │ │ │ ├── AttributeServiceEntryProvider.cs │ │ │ │ ├── RpcServiceAttribute.cs │ │ │ │ ├── RpcServiceBundleAttribute.cs │ │ │ │ ├── RpcServiceDescriptorAttribute.cs │ │ │ │ └── RpcServiceMetadataAttribute.cs │ │ │ ├── IClrServiceEntryFactory.cs │ │ │ └── Implementation │ │ │ │ └── ClrServiceEntryFactory.cs │ │ └── ServiceHostAbstract.cs │ │ └── ServiceEntry.cs ├── Serialization │ ├── ISerializer.cs │ └── Implementation │ │ ├── JsonSerializer.cs │ │ ├── StringByteArraySerializer.cs │ │ └── StringObjectSerializer.cs ├── ServiceDescriptor.cs └── Transport │ ├── Codec │ ├── ITransportMessageCodecFactory.cs │ ├── ITransportMessageDecoder.cs │ ├── ITransportMessageEncoder.cs │ └── Implementation │ │ ├── JsonTransportMessageCodecFactory.cs │ │ ├── JsonTransportMessageDecoder.cs │ │ └── JsonTransportMessageEncoder.cs │ ├── IMessageListener.cs │ ├── IMessageSender.cs │ ├── ITransportClient.cs │ ├── ITransportClientFactory.cs │ └── Implementation │ ├── MessageListener.cs │ └── TransportClient.cs ├── examples ├── Echo.Client │ ├── Echo.Client.csproj │ ├── Program.cs │ └── Properties │ │ ├── AssemblyInfo.cs │ │ └── PublishProfiles │ │ ├── Default-publish.ps1 │ │ └── publish-module.psm1 ├── Echo.Common │ ├── Echo.Common.csproj │ ├── Properties │ │ └── AssemblyInfo.cs │ └── UserService.cs ├── Echo.Server │ ├── Echo.Server.csproj │ ├── Program.cs │ └── Properties │ │ └── AssemblyInfo.cs └── performances │ ├── Performances.Net.Client │ ├── Performances.Net.Client.csproj │ ├── Program.cs │ └── Properties │ │ └── AssemblyInfo.cs │ ├── Performances.Net.Server │ ├── Performances.Net.Server.csproj │ ├── Program.cs │ └── Properties │ │ └── AssemblyInfo.cs │ ├── Performances.NetCoreApp.Client │ ├── Performances.NetCoreApp.Client.csproj │ ├── Program.cs │ └── Properties │ │ └── AssemblyInfo.cs │ └── Performances.NetCoreApp.Server │ ├── Performances.NetCoreApp.Server.csproj │ ├── Program.cs │ └── Properties │ └── AssemblyInfo.cs ├── extensions ├── codecs │ └── Rabbit.Rpc.Codec.ProtoBuffer │ │ ├── Messages │ │ ├── ProtoBufferDynamicItem.cs │ │ ├── ProtoBufferRemoteInvokeMessage.cs │ │ ├── ProtoBufferRemoteInvokeResultMessage.cs │ │ └── ProtoBufferTransportMessage.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── ProtoBufferTransportMessageCodecFactory.cs │ │ ├── ProtoBufferTransportMessageDecoder.cs │ │ ├── ProtoBufferTransportMessageEncoder.cs │ │ ├── Rabbit.Rpc.Codec.ProtoBuffer.csproj │ │ ├── Rabbit.Rpc.Codec.ProtoBuffer.csproj.migration_in_place_backup │ │ ├── RpcServiceCollectionExtensions.cs │ │ └── Utilitys │ │ └── SerializerUtilitys.cs ├── coordinates │ └── Rabbit.Rpc.Coordinate.Zookeeper │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── Rabbit.Rpc.Coordinate.Zookeeper.csproj │ │ ├── RpcServiceCollectionExtensions.cs │ │ └── ZooKeeperServiceRouteManager.cs └── transports │ └── Rabbit.Transport.DotNetty │ ├── Adaper │ └── TransportMessageChannelHandlerAdapter.cs │ ├── DotNettyMessageSender.cs │ ├── DotNettyServerMessageListener.cs │ ├── DotNettyTransportClientFactory.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Rabbit.Transport.DotNetty.csproj │ └── RpcServiceCollectionExtensions.cs ├── tests └── Rabbit.Rpc.Tests │ ├── AddressSelectors │ ├── PollingAddressSelectorTests.cs │ └── RandomAddressSelectorTests.cs │ ├── ModelEqualsTests.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Rabbit.Rpc.Tests.csproj │ └── ServiceRouteManagers │ ├── ServiceRouteManagerTests.cs │ ├── SharedFileServiceRouteManagerTests.cs │ └── ZooKeeperServiceRouteManagerTests.cs └── tools └── Rabbit.Rpc.ClientGenerator ├── Program.cs ├── Properties └── AssemblyInfo.cs └── Rabbit.Rpc.ClientGenerator.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rabbit RPC 2 | A lightweight cross-platform RPC. 3 | ## Features 4 | 1. Apache License 2.0 protocol open source 5 | 2. Supports client load balancing (polling and random) 6 | 3. Support ZooKeeper and file sharing the service coordination 7 | 4. Runtime client proxy generation (based Roslyn) 8 | 5. Pre-generated client agent (based Roslyn) 9 | 6. Abstract codec (JSON and ProtoBuffer) 10 | 7. Abstract transmission channel (DotNetty) 11 | 8. Exception information transfer (Local exceptions to the server runtime can be passed to the client) 12 | 9. **NET Core Project structure** 13 | 10. **Cross-platform** 14 | 15 | ## Overview 16 | ![](http://images2015.cnblogs.com/blog/384997/201607/384997-20160708082111186-595090265.png) 17 | ### Rabbit.Rpc 18 | 1. Rpc core class library, has the following functions: 19 | 2. Service Id generation 20 | 3. Transfer the message model 21 | 4. Type conversion 22 | 5. Service routing abstraction 23 | 6. Serializer abstraction (the default provides JSON serializer) 24 | 7. Transport abstraction 25 | 8. Codec abstraction (default provides JSON codec implementation) 26 | 9. Client runtime (address resolver, address selector, remote call service) 27 | 10. Service-side runtime (service entry management, service executor, service discovery abstraction, RpcServiceAttribute tagging service discovery implementation) 28 | 29 | ### Rabbit.Rpc.ProxyGenerator 30 | Service Agent Builder, provides features: 31 | 32 | 1. Service agent implementation generation 33 | 2. Service agent instance creation 34 | 35 | ### extensions 36 | #### Rabbit.Rpc.Codec.ProtoBuffer 37 | ProtoBuffer protocol codec implementation. 38 | 39 | #### Rabbit.Rpc.Coordinate.Zookeeper 40 | Service Routing Management Based on ZooKeeper. 41 | 42 | #### Rabbit.Transport.DotNetty 43 | Implementation of DotNetty Transmission. 44 | 45 | ### tools 46 | #### Rabbit.Rpc.Tests 47 | Unit test project. 48 | 49 | #### Rabbit.Rpc.ClientGenerator 50 | Pre-production service agent tool, provides the following functions: 51 | 52 | 1. Generate the service proxy implementation code file 53 | 2. Generate the service agent to implement the assembly file 54 | 55 | ## Performance Testing 56 | Test environment 57 | 58 | OS | CPU | Memory | disk | network | VM 59 | ------------ | ------------- | ------------- | ------------- | ------------- | ------------- 60 | Windows 10 x64 | I7 3610QM | 16GB | SSD | 127.0.0.1 | no 61 | Ubuntu 16.04 x64 | I7 3610QM | 4GB | SSD | 127.0.0.1 | yes 62 | 63 | ### Windows10 + NETCoreApp1.0 + JSON protocol 64 | loop 10,000 65 | first    2626ms 66 | second 2597ms 67 | third   2581ms 68 | 69 | ### Windows10 + NETCoreApp1.0 + ProtoBuffer protocol 70 | loop 10,000 71 | first    2567ms 72 | second 2617ms 73 | third   2474ms 74 | 75 | ### Ubuntu16.04-x64 + NETCoreApp1.0 + JSON protocol 76 | loop 10,000 77 | first    3205ms 78 | second 3252ms 79 | third   2837ms 80 | 81 | ### Ubuntu16.04-x64 + NETCoreApp1.0 + ProtoBuffer protocol 82 | loop 10,000 83 | first    3391ms 84 | second 3391ms 85 | third   3574ms 86 | 87 | ## related articles 88 | * [拥抱.NET Core,跨平台的轻量级RPC:Rabbit.Rpc](http://www.cnblogs.com/ants/p/5652132.html) 89 | * [.NET轻量级RPC框架:Rabbit.Rpc](http://www.cnblogs.com/ants/p/5605754.html) 90 | 91 | ## communication 92 | * [QQ Group:384413261(RabbitHub)](http://jq.qq.com/?_wv=1027&k=29DzAfj) 93 | * [Email:majian159@live.com](mailto:majian159@live.com) 94 | -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/IServiceProxyFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.ProxyGenerator 4 | { 5 | /// 6 | /// 一个抽象的服务代理工厂。 7 | /// 8 | public interface IServiceProxyFactory 9 | { 10 | /// 11 | /// 创建服务代理。 12 | /// 13 | /// 代理类型。 14 | /// 服务代理实例。 15 | object CreateProxy(Type proxyType); 16 | } 17 | 18 | /// 19 | /// 服务代理工厂扩展。 20 | /// 21 | public static class ServiceProxyFactoryExtensions 22 | { 23 | /// 24 | /// 创建服务代理。 25 | /// 26 | /// 服务接口类型。 27 | /// 服务代理工厂。 28 | /// 代理类型。 29 | /// 服务代理实例。 30 | public static T CreateProxy(this IServiceProxyFactory serviceProxyFactory, Type proxyType) 31 | { 32 | return (T)serviceProxyFactory.CreateProxy(proxyType); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/IServiceProxyGenerater.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Rabbit.Rpc.ProxyGenerator 6 | { 7 | /// 8 | /// 一个抽象的服务代理生成器。 9 | /// 10 | public interface IServiceProxyGenerater 11 | { 12 | /// 13 | /// 生成服务代理。 14 | /// 15 | /// 需要被代理的接口类型。 16 | /// 服务代理实现。 17 | IEnumerable GenerateProxys(IEnumerable interfacTypes); 18 | 19 | /// 20 | /// 生成服务代理代码树。 21 | /// 22 | /// 需要被代理的接口类型。 23 | /// 代码树。 24 | SyntaxTree GenerateProxyTree(Type interfaceType); 25 | } 26 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/Implementation/ServiceProxyBase.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Convertibles; 2 | using Rabbit.Rpc.Messages; 3 | using Rabbit.Rpc.Runtime.Client; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace Rabbit.Rpc.ProxyGenerator.Implementation 8 | { 9 | /// 10 | /// 一个抽象的服务代理基类。 11 | /// 12 | public abstract class ServiceProxyBase 13 | { 14 | #region Field 15 | 16 | private readonly IRemoteInvokeService _remoteInvokeService; 17 | private readonly ITypeConvertibleService _typeConvertibleService; 18 | 19 | #endregion Field 20 | 21 | #region Constructor 22 | 23 | protected ServiceProxyBase(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService) 24 | { 25 | _remoteInvokeService = remoteInvokeService; 26 | _typeConvertibleService = typeConvertibleService; 27 | } 28 | 29 | #endregion Constructor 30 | 31 | #region Protected Method 32 | 33 | /// 34 | /// 远程调用。 35 | /// 36 | /// 返回类型。 37 | /// 参数字典。 38 | /// 服务Id。 39 | /// 调用结果。 40 | protected async Task Invoke(IDictionary parameters, string serviceId) 41 | { 42 | var message = await _remoteInvokeService.InvokeAsync(new RemoteInvokeContext 43 | { 44 | InvokeMessage = new RemoteInvokeMessage 45 | { 46 | Parameters = parameters, 47 | ServiceId = serviceId 48 | } 49 | }); 50 | 51 | if (message == null) 52 | return default(T); 53 | 54 | var result = _typeConvertibleService.Convert(message.Result, typeof(T)); 55 | 56 | return (T)result; 57 | } 58 | 59 | /// 60 | /// 远程调用。 61 | /// 62 | /// 参数字典。 63 | /// 服务Id。 64 | /// 调用任务。 65 | protected async Task Invoke(IDictionary parameters, string serviceId) 66 | { 67 | await _remoteInvokeService.InvokeAsync(new RemoteInvokeContext 68 | { 69 | InvokeMessage = new RemoteInvokeMessage 70 | { 71 | Parameters = parameters, 72 | ServiceId = serviceId 73 | } 74 | }); 75 | } 76 | 77 | #endregion Protected Method 78 | } 79 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/Implementation/ServiceProxyFactory.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Convertibles; 2 | using Rabbit.Rpc.Runtime.Client; 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace Rabbit.Rpc.ProxyGenerator.Implementation 8 | { 9 | /// 10 | /// 默认的服务代理工厂实现。 11 | /// 12 | public class ServiceProxyFactory : IServiceProxyFactory 13 | { 14 | #region Field 15 | 16 | private readonly IRemoteInvokeService _remoteInvokeService; 17 | private readonly ITypeConvertibleService _typeConvertibleService; 18 | 19 | #endregion Field 20 | 21 | #region Constructor 22 | 23 | public ServiceProxyFactory(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService) 24 | { 25 | _remoteInvokeService = remoteInvokeService; 26 | _typeConvertibleService = typeConvertibleService; 27 | } 28 | 29 | #endregion Constructor 30 | 31 | #region Implementation of IServiceProxyFactory 32 | 33 | /// 34 | /// 创建服务代理。 35 | /// 36 | /// 代理类型。 37 | /// 服务代理实例。 38 | public object CreateProxy(Type proxyType) 39 | { 40 | var instance = proxyType.GetTypeInfo().GetConstructors().First().Invoke(new object[] { _remoteInvokeService, _typeConvertibleService }); 41 | return instance; 42 | } 43 | 44 | #endregion Implementation of IServiceProxyFactory 45 | } 46 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc.ProxyGenerator")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("5105cb2c-5bfa-4106-84e9-f1101323c560")] -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/Rabbit.Rpc.ProxyGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Rpc客户端代理生成器。 5 | © RabbitHub. All rights reserved. 6 | 1.0.0-alpha1 7 | majian 8 | net45;netstandard1.6 9 | Rabbit.Rpc.ProxyGenerator 10 | Rabbit.Rpc.ProxyGenerator 11 | RabbitHub;RPC 12 | http://www.rabbithub.com/icon.png 13 | https://github.com/RabbitTeam/Rpc 14 | https://github.com/RabbitTeam/Rpc/blob/master/LICENSE 15 | 1.6.0 16 | false 17 | false 18 | false 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | $(DefineConstants);NET 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/Rabbit.Rpc.ProxyGenerator/RpcServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Rabbit.Rpc.ProxyGenerator.Implementation; 3 | 4 | namespace Rabbit.Rpc.ProxyGenerator 5 | { 6 | public static class RpcServiceCollectionExtensions 7 | { 8 | public static IRpcBuilder AddClientProxy(this IRpcBuilder builder) 9 | { 10 | var services = builder.Services; 11 | 12 | services.AddSingleton(); 13 | services.AddSingleton(); 14 | 15 | return builder; 16 | } 17 | 18 | public static IRpcBuilder AddClient(this IServiceCollection services) 19 | { 20 | return services 21 | .AddRpcCore() 22 | .AddClientRuntime() 23 | .AddClientProxy(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Address/AddressModel.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Rabbit.Rpc.Address 4 | { 5 | /// 6 | /// 一个抽象的地址模型。 7 | /// 8 | public abstract class AddressModel 9 | { 10 | /// 11 | /// 创建终结点。 12 | /// 13 | /// 14 | public abstract EndPoint CreateEndPoint(); 15 | 16 | /// 17 | /// 重写后的标识。 18 | /// 19 | /// 一个字符串。 20 | public abstract override string ToString(); 21 | 22 | #region Equality members 23 | 24 | /// Determines whether the specified object is equal to the current object. 25 | /// true if the specified object is equal to the current object; otherwise, false. 26 | /// The object to compare with the current object. 27 | public override bool Equals(object obj) 28 | { 29 | var model = obj as AddressModel; 30 | if (model == null) 31 | return false; 32 | 33 | if (obj.GetType() != GetType()) 34 | return false; 35 | 36 | return model.ToString() == ToString(); 37 | } 38 | 39 | /// Serves as the default hash function. 40 | /// A hash code for the current object. 41 | public override int GetHashCode() 42 | { 43 | return ToString().GetHashCode(); 44 | } 45 | 46 | public static bool operator ==(AddressModel model1, AddressModel model2) 47 | { 48 | return Equals(model1, model2); 49 | } 50 | 51 | public static bool operator !=(AddressModel model1, AddressModel model2) 52 | { 53 | return !Equals(model1, model2); 54 | } 55 | 56 | #endregion Equality members 57 | } 58 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Address/IpAddressModel.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RabbitTeam/RabbitCloud/8d42a11d1208f55117a411b4248a5abf336161e6/src/Rabbit.Rpc/Address/IpAddressModel.cs -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Convertibles/ITypeConvertibleProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Rabbit.Rpc.Convertibles 5 | { 6 | /// 7 | /// 类型转换。 8 | /// 9 | /// 需要转换的实例。 10 | /// 转换的类型。 11 | /// 转换之后的类型,如果无法转换则返回null。 12 | public delegate object TypeConvertDelegate(object instance, Type conversionType); 13 | 14 | /// 15 | /// 一个抽象的类型转换提供程序。 16 | /// 17 | public interface ITypeConvertibleProvider 18 | { 19 | /// 20 | /// 获取类型转换器。 21 | /// 22 | /// 类型转换器集合。 23 | IEnumerable GetConverters(); 24 | } 25 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Convertibles/ITypeConvertibleService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Convertibles 4 | { 5 | /// 6 | /// 一个抽象的类型转换服务。 7 | /// 8 | public interface ITypeConvertibleService 9 | { 10 | /// 11 | /// 转换。 12 | /// 13 | /// 需要转换的实例。 14 | /// 转换的类型。 15 | /// 转换之后的类型,如果无法转换则返回null。 16 | object Convert(object instance, Type conversionType); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Convertibles/Implementation/DefaultTypeConvertibleProvider.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Serialization; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | 6 | namespace Rabbit.Rpc.Convertibles.Implementation 7 | { 8 | /// 9 | /// 一个默认的类型转换提供程序。 10 | /// 11 | public class DefaultTypeConvertibleProvider : ITypeConvertibleProvider 12 | { 13 | private readonly ISerializer _serializer; 14 | 15 | public DefaultTypeConvertibleProvider(ISerializer serializer) 16 | { 17 | _serializer = serializer; 18 | } 19 | 20 | #region Implementation of ITypeConvertibleProvider 21 | 22 | /// 23 | /// 获取类型转换器。 24 | /// 25 | /// 类型转换器集合。 26 | public IEnumerable GetConverters() 27 | { 28 | yield return EnumTypeConvert; 29 | yield return SimpleTypeConvert; 30 | yield return ComplexTypeConvert; 31 | } 32 | 33 | #endregion Implementation of ITypeConvertibleProvider 34 | 35 | #region Private Method 36 | 37 | private static object EnumTypeConvert(object instance, Type conversionType) 38 | { 39 | if (instance == null || !conversionType.GetTypeInfo().IsEnum) 40 | return null; 41 | return Enum.Parse(conversionType, instance.ToString()); 42 | } 43 | 44 | private static object SimpleTypeConvert(object instance, Type conversionType) 45 | { 46 | if (instance is IConvertible && typeof(IConvertible).GetTypeInfo().IsAssignableFrom(conversionType)) 47 | return Convert.ChangeType(instance, conversionType); 48 | return null; 49 | } 50 | 51 | private object ComplexTypeConvert(object instance, Type conversionType) 52 | { 53 | return _serializer.Deserialize(instance, conversionType); 54 | } 55 | 56 | #endregion Private Method 57 | } 58 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Convertibles/Implementation/DefaultTypeConvertibleService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Rabbit.Rpc.Exceptions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | 8 | namespace Rabbit.Rpc.Convertibles.Implementation 9 | { 10 | /// 11 | /// 一个默认的类型转换服务。 12 | /// 13 | public class DefaultTypeConvertibleService : ITypeConvertibleService 14 | { 15 | #region Field 16 | 17 | private readonly IEnumerable _converters; 18 | private readonly ILogger _logger; 19 | 20 | #endregion Field 21 | 22 | #region Constructor 23 | 24 | public DefaultTypeConvertibleService(IEnumerable providers, ILogger logger) 25 | { 26 | _logger = logger; 27 | providers = providers.ToArray(); 28 | if (_logger.IsEnabled(LogLevel.Debug)) 29 | _logger.LogDebug($"发现了以下类型转换提供程序:{string.Join(",", providers.Select(p => p.ToString()))}。"); 30 | _converters = providers.SelectMany(p => p.GetConverters()).ToArray(); 31 | } 32 | 33 | #endregion Constructor 34 | 35 | #region Implementation of ITypeConvertibleService 36 | 37 | /// 38 | /// 转换。 39 | /// 40 | /// 需要转换的实例。 41 | /// 转换的类型。 42 | /// 转换之后的类型,如果无法转换则返回null。 43 | public object Convert(object instance, Type conversionType) 44 | { 45 | if (instance == null) 46 | throw new ArgumentNullException(nameof(instance)); 47 | if (conversionType == null) 48 | throw new ArgumentNullException(nameof(conversionType)); 49 | 50 | if (conversionType.GetTypeInfo().IsInstanceOfType(instance)) 51 | return instance; 52 | 53 | if (_logger.IsEnabled(LogLevel.Debug)) 54 | _logger.LogDebug($"准备将 {instance.GetType()} 转换为:{conversionType}。"); 55 | 56 | object result = null; 57 | foreach (var converter in _converters) 58 | { 59 | result = converter(instance, conversionType); 60 | if (result != null) 61 | break; 62 | } 63 | if (result != null) 64 | return result; 65 | var exception = new RpcException($"无法将实例:{instance}转换为{conversionType}。"); 66 | 67 | if (_logger.IsEnabled(LogLevel.Error)) 68 | _logger.LogError($"将 {instance.GetType()} 转换成 {conversionType} 时发生了错误。", exception); 69 | throw exception; 70 | } 71 | 72 | #endregion Implementation of ITypeConvertibleService 73 | } 74 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Exceptions/RpcCommunicationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Exceptions 4 | { 5 | /// 6 | /// RPC通讯异常(与服务端进行通讯时发生的异常)。 7 | /// 8 | public class RpcCommunicationException : RpcException 9 | { 10 | /// 11 | /// 初始化一个新的Rpc异常实例。 12 | /// 13 | /// 异常消息。 14 | /// 内部异常。 15 | public RpcCommunicationException(string message, Exception innerException = null) : base(message, innerException) 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Exceptions/RpcException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Exceptions 4 | { 5 | /// 6 | /// 一个基础的Rpc异常类。 7 | /// 8 | public class RpcException : Exception 9 | { 10 | /// 11 | /// 初始化一个新的Rpc异常实例。 12 | /// 13 | /// 异常消息。 14 | /// 内部异常。 15 | public RpcException(string message, Exception innerException = null) : base(message, innerException) 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Exceptions/RpcRemoteException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Exceptions 4 | { 5 | /// 6 | /// RPC远程执行异常(由服务端转发至客户端的异常信息)。 7 | /// 8 | public class RpcRemoteException : RpcException 9 | { 10 | /// 11 | /// 初始化一个新的Rpc异常实例。 12 | /// 13 | /// 异常消息。 14 | /// 内部异常。 15 | public RpcRemoteException(string message, Exception innerException = null) : base(message, innerException) 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Ids/IServiceIdGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Rabbit.Rpc.Ids 4 | { 5 | /// 6 | /// 一个抽象的服务Id生成器。 7 | /// 8 | public interface IServiceIdGenerator 9 | { 10 | /// 11 | /// 生成一个服务Id。 12 | /// 13 | /// 本地方法信息。 14 | /// 对应方法的唯一服务Id。 15 | string GenerateServiceId(MethodInfo method); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Ids/Implementation/DefaultServiceIdGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Rabbit.Rpc.Ids.Implementation 7 | { 8 | /// 9 | /// 一个默认的服务Id生成器。 10 | /// 11 | public class DefaultServiceIdGenerator : IServiceIdGenerator 12 | { 13 | private readonly ILogger _logger; 14 | 15 | public DefaultServiceIdGenerator(ILogger logger) 16 | { 17 | _logger = logger; 18 | } 19 | 20 | #region Implementation of IServiceIdFactory 21 | 22 | /// 23 | /// 生成一个服务Id。 24 | /// 25 | /// 本地方法信息。 26 | /// 对应方法的唯一服务Id。 27 | public string GenerateServiceId(MethodInfo method) 28 | { 29 | if (method == null) 30 | throw new ArgumentNullException(nameof(method)); 31 | var type = method.DeclaringType; 32 | if (type == null) 33 | throw new ArgumentNullException(nameof(method.DeclaringType), "方法的定义类型不能为空。"); 34 | 35 | var id = $"{type.FullName}.{method.Name}"; 36 | var parameters = method.GetParameters(); 37 | if (parameters.Any()) 38 | { 39 | id += "_" + string.Join("_", parameters.Select(i => i.Name)); 40 | } 41 | if (_logger.IsEnabled(LogLevel.Debug)) 42 | _logger.LogDebug($"为方法:{method}生成服务Id:{id}。"); 43 | return id; 44 | } 45 | 46 | #endregion Implementation of IServiceIdFactory 47 | } 48 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Logging/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | /*using System; 2 | 3 | namespace Rabbit.Rpc.Logging 4 | { 5 | public class ConsoleLogger : ConsoleLogger, ILogger 6 | { 7 | } 8 | 9 | public class ConsoleLogger : ILogger 10 | { 11 | #region Implementation of ILogger 12 | 13 | /// 14 | /// 判断日志记录器是否开启。 15 | /// 16 | /// 日志等级。 17 | /// 如果开启返回true,否则返回false。 18 | public bool IsEnabled(LogLevel level) 19 | { 20 | return (int)level > 2; 21 | } 22 | 23 | /// 24 | /// 记录日志。 25 | /// 26 | /// 日志等级。 27 | /// 消息。 28 | /// 异常。 29 | /// 任务。 30 | public void Log(LogLevel level, string message, Exception exception = null) 31 | { 32 | Console.ResetColor(); 33 | var color = Console.ForegroundColor; 34 | 35 | switch (level) 36 | { 37 | case LogLevel.Trace: 38 | color = ConsoleColor.DarkGray; 39 | break; 40 | 41 | case LogLevel.Debug: 42 | color = ConsoleColor.Gray; 43 | break; 44 | 45 | case LogLevel.Information: 46 | color = ConsoleColor.DarkBlue; 47 | break; 48 | 49 | case LogLevel.Warning: 50 | color = ConsoleColor.Yellow; 51 | break; 52 | 53 | case LogLevel.Error: 54 | color = ConsoleColor.DarkRed; 55 | break; 56 | 57 | case LogLevel.Fatal: 58 | color = ConsoleColor.Red; 59 | break; 60 | } 61 | 62 | Console.ForegroundColor = color; 63 | 64 | Console.WriteLine($"level:{level}"); 65 | Console.WriteLine($"message:{message}"); 66 | if (exception != null) 67 | Console.WriteLine($"exception:{exception}"); 68 | Console.WriteLine("========================================"); 69 | 70 | Console.ResetColor(); 71 | } 72 | 73 | #endregion Implementation of ILogger 74 | } 75 | }*/ -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Logging/ILogger.cs: -------------------------------------------------------------------------------- 1 | /*using System; 2 | 3 | namespace Rabbit.Rpc.Logging 4 | { 5 | /// 6 | /// 日志等级。 7 | /// 8 | public enum LogLevel 9 | { 10 | /// 11 | /// 追踪。 12 | /// 13 | Trace = 0, 14 | 15 | /// 16 | /// 调试。 17 | /// 18 | Debug = 1, 19 | 20 | /// 21 | /// 信息。 22 | /// 23 | Information = 2, 24 | 25 | /// 26 | /// 警告。 27 | /// 28 | Warning = 3, 29 | 30 | /// 31 | /// 错误。 32 | /// 33 | Error = 4, 34 | 35 | /// 36 | /// 致命错误。 37 | /// 38 | Fatal = 5 39 | } 40 | 41 | /// 42 | /// 一个抽象的日志记录器。 43 | /// 44 | /// 日志记录器类型。 45 | public interface ILogger : ILogger 46 | { 47 | } 48 | 49 | /// 50 | /// 一个抽象的日志记录器。 51 | /// 52 | public interface ILogger 53 | { 54 | /// 55 | /// 判断日志记录器是否开启。 56 | /// 57 | /// 日志等级。 58 | /// 如果开启返回true,否则返回false。 59 | bool IsEnabled(LogLevel level); 60 | 61 | /// 62 | /// 记录日志。 63 | /// 64 | /// 日志等级。 65 | /// 消息。 66 | /// 异常。 67 | /// 任务。 68 | void Log(LogLevel level, string message, Exception exception = null); 69 | } 70 | 71 | /// 72 | /// 日志记录器扩展。 73 | /// 74 | public static class LoggerExtensions 75 | { 76 | /// 77 | /// 追踪。 78 | /// 79 | /// 日志记录器。 80 | /// 消息。 81 | /// 异常信息。 82 | public static void Trace(this ILogger logger, string message, Exception exception = null) 83 | { 84 | logger.Log(LogLevel.Trace, message, exception); 85 | } 86 | 87 | /// 88 | /// 调试。 89 | /// 90 | /// 日志记录器。 91 | /// 消息。 92 | /// 异常信息。 93 | public static void Debug(this ILogger logger, string message, Exception exception = null) 94 | { 95 | logger.Log(LogLevel.Debug, message, exception); 96 | } 97 | 98 | /// 99 | /// 信息。 100 | /// 101 | /// 日志记录器。 102 | /// 消息。 103 | /// 异常信息。 104 | public static void Information(this ILogger logger, string message, Exception exception = null) 105 | { 106 | logger.Log(LogLevel.Information, message, exception); 107 | } 108 | 109 | /// 110 | /// 警告。 111 | /// 112 | /// 日志记录器。 113 | /// 消息。 114 | /// 异常信息。 115 | public static void Warning(this ILogger logger, string message, Exception exception = null) 116 | { 117 | logger.Log(LogLevel.Warning, message, exception); 118 | } 119 | 120 | /// 121 | /// 错误。 122 | /// 123 | /// 日志记录器。 124 | /// 消息。 125 | /// 异常信息。 126 | public static void Error(this ILogger logger, string message, Exception exception = null) 127 | { 128 | logger.Log(LogLevel.Error, message, exception); 129 | } 130 | 131 | /// 132 | /// 失败。 133 | /// 134 | /// 日志记录器。 135 | /// 消息。 136 | /// 异常信息。 137 | public static void Fatal(this ILogger logger, string message, Exception exception = null) 138 | { 139 | logger.Log(LogLevel.Fatal, message, exception); 140 | } 141 | } 142 | }*/ -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Logging/NullLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | 4 | namespace Rabbit.Rpc.Logging 5 | { 6 | /// 7 | /// 一个空的日志记录器。 8 | /// 9 | public sealed class NullLogger : NullLogger, ILogger 10 | { 11 | } 12 | 13 | /// 14 | /// 一个空的日志记录器。 15 | /// 16 | public class NullLogger : ILogger 17 | { 18 | public static NullLogger Instance { get; } = new NullLogger(); 19 | 20 | #region Implementation of ILogger 21 | 22 | /// Writes a log entry. 23 | /// Entry will be written on this level. 24 | /// Id of the event. 25 | /// The entry to be written. Can be also an object. 26 | /// The exception related to this entry. 27 | /// Function to create a string message of the and . 28 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 29 | { 30 | } 31 | 32 | /// 33 | /// Checks if the given is enabled. 34 | /// 35 | /// level to be checked. 36 | /// true if enabled. 37 | public bool IsEnabled(LogLevel logLevel) 38 | { 39 | return false; 40 | } 41 | 42 | /// Begins a logical operation scope. 43 | /// The identifier for the scope. 44 | /// An IDisposable that ends the logical operation scope on dispose. 45 | public IDisposable BeginScope(TState state) 46 | { 47 | throw new NotImplementedException(); 48 | } 49 | 50 | #endregion Implementation of ILogger 51 | } 52 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Messages/RemoteInvokeMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Rabbit.Rpc.Messages 4 | { 5 | /// 6 | /// 远程调用消息。 7 | /// 8 | public class RemoteInvokeMessage 9 | { 10 | /// 11 | /// 服务Id。 12 | /// 13 | public string ServiceId { get; set; } 14 | 15 | /// 16 | /// 服务参数。 17 | /// 18 | public IDictionary Parameters { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Messages/RemoteInvokeResultMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Rabbit.Rpc.Messages 2 | { 3 | /// 4 | /// 远程调用结果消息。 5 | /// 6 | public class RemoteInvokeResultMessage 7 | { 8 | /// 9 | /// 异常消息。 10 | /// 11 | public string ExceptionMessage { get; set; } 12 | 13 | /// 14 | /// 结果内容。 15 | /// 16 | public object Result { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Messages/TransportMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Messages 4 | { 5 | /// 6 | /// 传输消息模型。 7 | /// 8 | public class TransportMessage 9 | { 10 | public TransportMessage() 11 | { 12 | } 13 | 14 | public TransportMessage(object content) 15 | { 16 | if (content == null) 17 | throw new ArgumentNullException(nameof(content)); 18 | 19 | Content = content; 20 | ContentType = content.GetType().FullName; 21 | } 22 | 23 | /// 24 | /// 消息Id。 25 | /// 26 | public string Id { get; set; } 27 | 28 | /// 29 | /// 消息内容。 30 | /// 31 | public object Content { get; set; } 32 | 33 | /// 34 | /// 内容类型。 35 | /// 36 | public string ContentType { get; set; } 37 | 38 | /// 39 | /// 是否调用消息。 40 | /// 41 | /// 如果是则返回true,否则返回false。 42 | public bool IsInvokeMessage() 43 | { 44 | return ContentType == typeof(RemoteInvokeMessage).FullName; 45 | } 46 | 47 | /// 48 | /// 是否是调用结果消息。 49 | /// 50 | /// 如果是则返回true,否则返回false。 51 | public bool IsInvokeResultMessage() 52 | { 53 | return ContentType == typeof(RemoteInvokeResultMessage).FullName; 54 | } 55 | 56 | /// 57 | /// 获取内容。 58 | /// 59 | /// 内容类型。 60 | /// 内容实例。 61 | public T GetContent() 62 | { 63 | return (T)Content; 64 | } 65 | 66 | /// 67 | /// 创建一个调用传输消息。 68 | /// 69 | /// 调用实例。 70 | /// 调用传输消息。 71 | public static TransportMessage CreateInvokeMessage(RemoteInvokeMessage invokeMessage) 72 | { 73 | return new TransportMessage(invokeMessage) 74 | { 75 | Id = Guid.NewGuid().ToString("N") 76 | }; 77 | } 78 | 79 | /// 80 | /// 创建一个调用结果传输消息。 81 | /// 82 | /// 消息Id。 83 | /// 调用结果实例。 84 | /// 调用结果传输消息。 85 | public static TransportMessage CreateInvokeResultMessage(string id, RemoteInvokeResultMessage invokeResultMessage) 86 | { 87 | return new TransportMessage(invokeResultMessage) 88 | { 89 | Id = id 90 | }; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("81911edf-5e21-4ac8-882a-7219696b9415")] -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Rabbit.Rpc.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 一个轻量级跨平台的Rpc。 5 | © RabbitHub. All rights reserved. 6 | 1.0.0-alpha1 7 | majian 8 | net45;net451;netstandard1.6 9 | Rabbit.Rpc 10 | Rabbit.Rpc 11 | RabbitHub;RPC 12 | http://www.rabbithub.com/icon.png 13 | https://github.com/RabbitTeam/Rpc 14 | https://github.com/RabbitTeam/Rpc/blob/master/LICENSE 15 | 1.6.0 16 | false 17 | false 18 | false 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | $(DefineConstants);NET 39 | 40 | 41 | 42 | $(DefineConstants);NET 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/IServiceRouteFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Routing 5 | { 6 | /// 7 | /// 一个抽象的服务路由工厂。 8 | /// 9 | public interface IServiceRouteFactory 10 | { 11 | /// 12 | /// 根据服务路由描述符创建服务路由。 13 | /// 14 | /// 服务路由描述符。 15 | /// 服务路由集合。 16 | Task> CreateServiceRoutesAsync(IEnumerable descriptors); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/IServiceRouteManager.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Routing.Implementation; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Rabbit.Rpc.Routing 8 | { 9 | /// 10 | /// 一个抽象的服务路由发现者。 11 | /// 12 | public interface IServiceRouteManager 13 | { 14 | /// 15 | /// 服务路由被创建。 16 | /// 17 | event EventHandler Created; 18 | 19 | /// 20 | /// 服务路由被删除。 21 | /// 22 | event EventHandler Removed; 23 | 24 | /// 25 | /// 服务路由被修改。 26 | /// 27 | event EventHandler Changed; 28 | 29 | /// 30 | /// 获取所有可用的服务路由信息。 31 | /// 32 | /// 服务路由集合。 33 | Task> GetRoutesAsync(); 34 | 35 | /// 36 | /// 设置服务路由。 37 | /// 38 | /// 服务路由集合。 39 | /// 一个任务。 40 | Task SetRoutesAsync(IEnumerable routes); 41 | 42 | /// 43 | /// 清空所有的服务路由。 44 | /// 45 | /// 一个任务。 46 | Task ClearAsync(); 47 | } 48 | 49 | /// 50 | /// 服务路由管理者扩展方法。 51 | /// 52 | public static class ServiceRouteManagerExtensions 53 | { 54 | /// 55 | /// 根据服务Id获取一个服务路由。 56 | /// 57 | /// 服务路由管理者。 58 | /// 服务Id。 59 | /// 服务路由。 60 | public static async Task GetAsync(this IServiceRouteManager serviceRouteManager, string serviceId) 61 | { 62 | return (await serviceRouteManager.GetRoutesAsync()).SingleOrDefault(i => i.ServiceDescriptor.Id == serviceId); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/Implementation/DefaultServiceRouteFactory.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using Rabbit.Rpc.Serialization; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Rabbit.Rpc.Routing.Implementation 9 | { 10 | /// 11 | /// 一个默认的服务路由工厂实现。 12 | /// 13 | public class DefaultServiceRouteFactory : IServiceRouteFactory 14 | { 15 | private readonly ISerializer _serializer; 16 | 17 | public DefaultServiceRouteFactory(ISerializer serializer) 18 | { 19 | _serializer = serializer; 20 | } 21 | 22 | #region Implementation of IServiceRouteFactory 23 | 24 | /// 25 | /// 根据服务路由描述符创建服务路由。 26 | /// 27 | /// 服务路由描述符。 28 | /// 服务路由集合。 29 | public Task> CreateServiceRoutesAsync(IEnumerable descriptors) 30 | { 31 | if (descriptors == null) 32 | throw new ArgumentNullException(nameof(descriptors)); 33 | 34 | descriptors = descriptors.ToArray(); 35 | var routes = new List(descriptors.Count()); 36 | routes.AddRange(descriptors.Select(descriptor => new ServiceRoute 37 | { 38 | Address = CreateAddress(descriptor.AddressDescriptors), 39 | ServiceDescriptor = descriptor.ServiceDescriptor 40 | })); 41 | 42 | return Task.FromResult(routes.AsEnumerable()); 43 | } 44 | 45 | #endregion Implementation of IServiceRouteFactory 46 | 47 | private IEnumerable CreateAddress(IEnumerable descriptors) 48 | { 49 | if (descriptors == null) 50 | yield break; 51 | 52 | foreach (var descriptor in descriptors) 53 | { 54 | var addressType = Type.GetType(descriptor.Type); 55 | yield return (AddressModel)_serializer.Deserialize(descriptor.Value, addressType); 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/Implementation/ServiceRouteManagerBase.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Serialization; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Rabbit.Rpc.Routing.Implementation 8 | { 9 | /// 10 | /// 服务路由事件参数。 11 | /// 12 | public class ServiceRouteEventArgs 13 | { 14 | public ServiceRouteEventArgs(ServiceRoute route) 15 | { 16 | Route = route; 17 | } 18 | 19 | /// 20 | /// 服务路由信息。 21 | /// 22 | public ServiceRoute Route { get; private set; } 23 | } 24 | 25 | /// 26 | /// 服务路由变更事件参数。 27 | /// 28 | public class ServiceRouteChangedEventArgs : ServiceRouteEventArgs 29 | { 30 | public ServiceRouteChangedEventArgs(ServiceRoute route, ServiceRoute oldRoute) : base(route) 31 | { 32 | OldRoute = oldRoute; 33 | } 34 | 35 | /// 36 | /// 旧的服务路由信息。 37 | /// 38 | public ServiceRoute OldRoute { get; set; } 39 | } 40 | 41 | /// 42 | /// 服务路由管理者基类。 43 | /// 44 | public abstract class ServiceRouteManagerBase : IServiceRouteManager 45 | { 46 | private readonly ISerializer _serializer; 47 | private EventHandler _created; 48 | private EventHandler _removed; 49 | private EventHandler _changed; 50 | 51 | protected ServiceRouteManagerBase(ISerializer serializer) 52 | { 53 | _serializer = serializer; 54 | } 55 | 56 | #region Implementation of IServiceRouteManager 57 | 58 | /// 59 | /// 服务路由被创建。 60 | /// 61 | public event EventHandler Created 62 | { 63 | add { _created += value; } 64 | remove { _created -= value; } 65 | } 66 | 67 | /// 68 | /// 服务路由被删除。 69 | /// 70 | public event EventHandler Removed 71 | { 72 | add { _removed += value; } 73 | remove { _removed -= value; } 74 | } 75 | 76 | /// 77 | /// 服务路由被修改。 78 | /// 79 | public event EventHandler Changed 80 | { 81 | add { _changed += value; } 82 | remove { _changed -= value; } 83 | } 84 | 85 | /// 86 | /// 获取所有可用的服务路由信息。 87 | /// 88 | /// 服务路由集合。 89 | public abstract Task> GetRoutesAsync(); 90 | 91 | /// 92 | /// 设置服务路由。 93 | /// 94 | /// 服务路由集合。 95 | /// 一个任务。 96 | Task IServiceRouteManager.SetRoutesAsync(IEnumerable routes) 97 | { 98 | if (routes == null) 99 | throw new ArgumentNullException(nameof(routes)); 100 | 101 | var descriptors = routes.Where(route => route != null).Select(route => new ServiceRouteDescriptor 102 | { 103 | AddressDescriptors = route.Address?.Select(address => new ServiceAddressDescriptor 104 | { 105 | Type = address.GetType().FullName, 106 | Value = _serializer.Serialize(address) 107 | }) ?? Enumerable.Empty(), 108 | ServiceDescriptor = route.ServiceDescriptor 109 | }); 110 | 111 | return SetRoutesAsync(descriptors); 112 | } 113 | 114 | /// 115 | /// 清空所有的服务路由。 116 | /// 117 | /// 一个任务。 118 | public abstract Task ClearAsync(); 119 | 120 | #endregion Implementation of IServiceRouteManager 121 | 122 | /// 123 | /// 设置服务路由。 124 | /// 125 | /// 服务路由集合。 126 | /// 一个任务。 127 | protected abstract Task SetRoutesAsync(IEnumerable routes); 128 | 129 | protected void OnCreated(params ServiceRouteEventArgs[] args) 130 | { 131 | if (_created == null) 132 | return; 133 | 134 | foreach (var arg in args) 135 | _created(this, arg); 136 | } 137 | 138 | protected void OnChanged(params ServiceRouteChangedEventArgs[] args) 139 | { 140 | if (_changed == null) 141 | return; 142 | 143 | foreach (var arg in args) 144 | _changed(this, arg); 145 | } 146 | 147 | protected void OnRemoved(params ServiceRouteEventArgs[] args) 148 | { 149 | if (_removed == null) 150 | return; 151 | 152 | foreach (var arg in args) 153 | _removed(this, arg); 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/ServiceRoute.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Rabbit.Rpc.Routing 6 | { 7 | /// 8 | /// 服务路由。 9 | /// 10 | public class ServiceRoute 11 | { 12 | /// 13 | /// 服务可用地址。 14 | /// 15 | public IEnumerable Address { get; set; } 16 | 17 | /// 18 | /// 服务描述符。 19 | /// 20 | public ServiceDescriptor ServiceDescriptor { get; set; } 21 | 22 | #region Equality members 23 | 24 | /// Determines whether the specified object is equal to the current object. 25 | /// true if the specified object is equal to the current object; otherwise, false. 26 | /// The object to compare with the current object. 27 | public override bool Equals(object obj) 28 | { 29 | var model = obj as ServiceRoute; 30 | if (model == null) 31 | return false; 32 | 33 | if (obj.GetType() != GetType()) 34 | return false; 35 | 36 | if (model.ServiceDescriptor != ServiceDescriptor) 37 | return false; 38 | 39 | return model.Address.Count() == Address.Count() && model.Address.All(addressModel => Address.Contains(addressModel)); 40 | } 41 | 42 | /// Serves as the default hash function. 43 | /// A hash code for the current object. 44 | public override int GetHashCode() 45 | { 46 | return ToString().GetHashCode(); 47 | } 48 | 49 | public static bool operator ==(ServiceRoute model1, ServiceRoute model2) 50 | { 51 | return Equals(model1, model2); 52 | } 53 | 54 | public static bool operator !=(ServiceRoute model1, ServiceRoute model2) 55 | { 56 | return !Equals(model1, model2); 57 | } 58 | 59 | #endregion Equality members 60 | } 61 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Routing/ServiceRouteDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using Rabbit.Rpc.Serialization; 3 | using System.Collections.Generic; 4 | 5 | namespace Rabbit.Rpc.Routing 6 | { 7 | /// 8 | /// 服务地址描述符。 9 | /// 10 | public class ServiceAddressDescriptor 11 | { 12 | /// 13 | /// 地址类型。 14 | /// 15 | public string Type { get; set; } 16 | 17 | /// 18 | /// 地址值。 19 | /// 20 | public string Value { get; set; } 21 | 22 | /// 23 | /// 创建一个描述符。 24 | /// 25 | /// 地址模型类型。 26 | /// 地址模型实例。 27 | /// 序列化器。 28 | /// 服务地址描述符。 29 | public static ServiceAddressDescriptor CreateDescriptor(T address, ISerializer serializer) where T : AddressModel, new() 30 | { 31 | return new ServiceAddressDescriptor 32 | { 33 | Type = typeof(T).FullName, 34 | Value = serializer.Serialize(address) 35 | }; 36 | } 37 | } 38 | 39 | /// 40 | /// 服务路由描述符。 41 | /// 42 | public class ServiceRouteDescriptor 43 | { 44 | /// 45 | /// 服务地址描述符集合。 46 | /// 47 | public IEnumerable AddressDescriptors { get; set; } 48 | 49 | /// 50 | /// 服务描述符。 51 | /// 52 | public ServiceDescriptor ServiceDescriptor { get; set; } 53 | } 54 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/IAddressResolver.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers 5 | { 6 | /// 7 | /// 一个抽象的服务地址解析器。 8 | /// 9 | public interface IAddressResolver 10 | { 11 | /// 12 | /// 解析服务地址。 13 | /// 14 | /// 服务Id。 15 | /// 服务地址模型。 16 | Task Resolver(string serviceId); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/Implementation/DefaultAddressResolver.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Rabbit.Rpc.Address; 3 | using Rabbit.Rpc.Routing; 4 | using Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors; 5 | using Rabbit.Rpc.Runtime.Client.HealthChecks; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation 11 | { 12 | /// 13 | /// 一个人默认的服务地址解析器。 14 | /// 15 | public class DefaultAddressResolver : IAddressResolver 16 | { 17 | #region Field 18 | 19 | private readonly IServiceRouteManager _serviceRouteManager; 20 | private readonly ILogger _logger; 21 | private readonly IAddressSelector _addressSelector; 22 | private readonly IHealthCheckService _healthCheckService; 23 | 24 | #endregion Field 25 | 26 | #region Constructor 27 | 28 | public DefaultAddressResolver(IServiceRouteManager serviceRouteManager, ILogger logger, IAddressSelector addressSelector, IHealthCheckService healthCheckService) 29 | { 30 | _serviceRouteManager = serviceRouteManager; 31 | _logger = logger; 32 | _addressSelector = addressSelector; 33 | _healthCheckService = healthCheckService; 34 | } 35 | 36 | #endregion Constructor 37 | 38 | #region Implementation of IAddressResolver 39 | 40 | /// 41 | /// 解析服务地址。 42 | /// 43 | /// 服务Id。 44 | /// 服务地址模型。 45 | public async Task Resolver(string serviceId) 46 | { 47 | if (_logger.IsEnabled(LogLevel.Debug)) 48 | _logger.LogDebug($"准备为服务id:{serviceId},解析可用地址。"); 49 | var descriptors = await _serviceRouteManager.GetRoutesAsync(); 50 | var descriptor = descriptors.FirstOrDefault(i => i.ServiceDescriptor.Id == serviceId); 51 | 52 | if (descriptor == null) 53 | { 54 | if (_logger.IsEnabled(LogLevel.Warning)) 55 | _logger.LogWarning($"根据服务id:{serviceId},找不到相关服务信息。"); 56 | return null; 57 | } 58 | 59 | var address = new List(); 60 | foreach (var addressModel in descriptor.Address) 61 | { 62 | await _healthCheckService.Monitor(addressModel); 63 | if (!await _healthCheckService.IsHealth(addressModel)) 64 | continue; 65 | 66 | address.Add(addressModel); 67 | } 68 | 69 | var hasAddress = address.Any(); 70 | if (!hasAddress) 71 | { 72 | if (_logger.IsEnabled(LogLevel.Warning)) 73 | _logger.LogWarning($"根据服务id:{serviceId},找不到可用的地址。"); 74 | return null; 75 | } 76 | 77 | if (_logger.IsEnabled(LogLevel.Information)) 78 | _logger.LogInformation($"根据服务id:{serviceId},找到以下可用地址:{string.Join(",", address.Select(i => i.ToString()))}。"); 79 | 80 | return await _addressSelector.SelectAsync(new AddressSelectContext 81 | { 82 | Descriptor = descriptor.ServiceDescriptor, 83 | Address = address 84 | }); 85 | } 86 | 87 | #endregion Implementation of IAddressResolver 88 | } 89 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/Implementation/Selectors/IAddressSelector.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors 6 | { 7 | /// 8 | /// 地址选择上下文。 9 | /// 10 | public class AddressSelectContext 11 | { 12 | /// 13 | /// 服务描述符。 14 | /// 15 | public ServiceDescriptor Descriptor { get; set; } 16 | 17 | /// 18 | /// 服务可用地址。 19 | /// 20 | public IEnumerable Address { get; set; } 21 | } 22 | 23 | /// 24 | /// 一个抽象的地址选择器。 25 | /// 26 | public interface IAddressSelector 27 | { 28 | /// 29 | /// 选择一个地址。 30 | /// 31 | /// 地址选择上下文。 32 | /// 地址模型。 33 | Task SelectAsync(AddressSelectContext context); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorBase.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation 7 | { 8 | /// 9 | /// 地址选择器基类。 10 | /// 11 | public abstract class AddressSelectorBase : IAddressSelector 12 | { 13 | #region Implementation of IAddressSelector 14 | 15 | /// 16 | /// 选择一个地址。 17 | /// 18 | /// 地址选择上下文。 19 | /// 地址模型。 20 | Task IAddressSelector.SelectAsync(AddressSelectContext context) 21 | { 22 | if (context == null) 23 | throw new ArgumentNullException(nameof(context)); 24 | if (context.Descriptor == null) 25 | throw new ArgumentNullException(nameof(context.Descriptor)); 26 | if (context.Address == null) 27 | throw new ArgumentNullException(nameof(context.Address)); 28 | 29 | var address = context.Address.ToArray(); 30 | if (!address.Any()) 31 | throw new ArgumentException("没有任何地址信息。", nameof(context.Address)); 32 | 33 | return address.Length == 1 ? Task.FromResult(address[0]) : SelectAsync(context); 34 | } 35 | 36 | #endregion Implementation of IAddressSelector 37 | 38 | /// 39 | /// 选择一个地址。 40 | /// 41 | /// 地址选择上下文。 42 | /// 地址模型。 43 | protected abstract Task SelectAsync(AddressSelectContext context); 44 | } 45 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/PollingAddressSelector.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using Rabbit.Rpc.Routing; 3 | using Rabbit.Rpc.Routing.Implementation; 4 | using Rabbit.Rpc.Runtime.Client.HealthChecks; 5 | using System; 6 | using System.Collections.Concurrent; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation 13 | { 14 | /// 15 | /// 轮询的地址选择器。 16 | /// 17 | public class PollingAddressSelector : AddressSelectorBase 18 | { 19 | private readonly IHealthCheckService _healthCheckService; 20 | 21 | private readonly ConcurrentDictionary> _concurrent = 22 | new ConcurrentDictionary>(); 23 | 24 | public PollingAddressSelector(IServiceRouteManager serviceRouteManager, IHealthCheckService healthCheckService) 25 | { 26 | _healthCheckService = healthCheckService; 27 | //路由发生变更时重建地址条目。 28 | serviceRouteManager.Changed += ServiceRouteManager_Removed; 29 | serviceRouteManager.Removed += ServiceRouteManager_Removed; 30 | } 31 | 32 | #region Overrides of AddressSelectorBase 33 | 34 | /// 35 | /// 选择一个地址。 36 | /// 37 | /// 地址选择上下文。 38 | /// 地址模型。 39 | protected override async Task SelectAsync(AddressSelectContext context) 40 | { 41 | var key = GetCacheKey(context.Descriptor); 42 | //根据服务id缓存服务地址。 43 | var addressEntry = _concurrent.GetOrAdd(key, k => new Lazy(() => new AddressEntry(context.Address))).Value; 44 | 45 | AddressModel addressModel; 46 | do 47 | { 48 | addressModel = addressEntry.GetAddress(); 49 | } while (await _healthCheckService.IsHealth(addressModel) == false); 50 | return addressModel; 51 | } 52 | 53 | #endregion Overrides of AddressSelectorBase 54 | 55 | #region Private Method 56 | 57 | private static string GetCacheKey(ServiceDescriptor descriptor) 58 | { 59 | return descriptor.Id; 60 | } 61 | 62 | private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) 63 | { 64 | var key = GetCacheKey(e.Route.ServiceDescriptor); 65 | Lazy value; 66 | _concurrent.TryRemove(key, out value); 67 | } 68 | 69 | #endregion Private Method 70 | 71 | #region Help Class 72 | 73 | protected class AddressEntry 74 | { 75 | #region Field 76 | 77 | private int _index; 78 | private int _lock; 79 | private readonly int _maxIndex; 80 | private readonly AddressModel[] _address; 81 | 82 | #endregion Field 83 | 84 | #region Constructor 85 | 86 | public AddressEntry(IEnumerable address) 87 | { 88 | _address = address.ToArray(); 89 | _maxIndex = _address.Length - 1; 90 | } 91 | 92 | #endregion Constructor 93 | 94 | #region Public Method 95 | 96 | public AddressModel GetAddress() 97 | { 98 | while (true) 99 | { 100 | //如果无法得到锁则等待 101 | if (Interlocked.Exchange(ref _lock, 1) != 0) 102 | { 103 | default(SpinWait).SpinOnce(); 104 | continue; 105 | } 106 | 107 | var address = _address[_index]; 108 | 109 | //设置为下一个 110 | if (_maxIndex > _index) 111 | _index++; 112 | else 113 | _index = 0; 114 | 115 | //释放锁 116 | Interlocked.Exchange(ref _lock, 0); 117 | 118 | return address; 119 | } 120 | } 121 | 122 | #endregion Public Method 123 | } 124 | 125 | #endregion Help Class 126 | } 127 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RandomAddressSelector.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation 7 | { 8 | /// 9 | /// 一个随机的地址选择器。 10 | /// 11 | public class RandomAddressSelector : AddressSelectorBase 12 | { 13 | #region Field 14 | 15 | private readonly Func _generate; 16 | private readonly Random _random; 17 | 18 | #endregion Field 19 | 20 | #region Constructor 21 | 22 | /// 23 | /// 初始化一个以Random生成随机数的随机地址选择器。 24 | /// 25 | public RandomAddressSelector() 26 | { 27 | _random = new Random(); 28 | _generate = (min, max) => _random.Next(min, max); 29 | } 30 | 31 | /// 32 | /// 初始化一个自定义的随机地址选择器。 33 | /// 34 | /// 随机数生成委托,第一个参数为最小值,第二个参数为最大值(不可以超过该值)。 35 | public RandomAddressSelector(Func generate) 36 | { 37 | if (generate == null) 38 | throw new ArgumentNullException(nameof(generate)); 39 | _generate = generate; 40 | } 41 | 42 | #endregion Constructor 43 | 44 | #region Overrides of AddressSelectorBase 45 | 46 | /// 47 | /// 选择一个地址。 48 | /// 49 | /// 地址选择上下文。 50 | /// 地址模型。 51 | protected override Task SelectAsync(AddressSelectContext context) 52 | { 53 | var address = context.Address.ToArray(); 54 | var length = address.Length; 55 | 56 | var index = _generate(0, length); 57 | return Task.FromResult(address[index]); 58 | } 59 | 60 | #endregion Overrides of AddressSelectorBase 61 | } 62 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/HealthChecks/IHealthCheckService.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Runtime.Client.HealthChecks 5 | { 6 | /// 7 | /// 一个抽象的健康检查服务。 8 | /// 9 | public interface IHealthCheckService 10 | { 11 | /// 12 | /// 监控一个地址。 13 | /// 14 | /// 地址模型。 15 | /// 一个任务。 16 | Task Monitor(AddressModel address); 17 | 18 | /// 19 | /// 判断一个地址是否健康。 20 | /// 21 | /// 地址模型。 22 | /// 健康返回true,否则返回false。 23 | Task IsHealth(AddressModel address); 24 | 25 | /// 26 | /// 标记一个地址为失败的。 27 | /// 28 | /// 地址模型。 29 | /// 一个任务。 30 | Task MarkFailure(AddressModel address); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/IRemoteInvokeService.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Rabbit.Rpc.Runtime.Client 6 | { 7 | /// 8 | /// 一个抽象的远程调用服务。 9 | /// 10 | public interface IRemoteInvokeService 11 | { 12 | /// 13 | /// 调用。 14 | /// 15 | /// 调用上下文。 16 | /// 远程调用结果消息模型。 17 | Task InvokeAsync(RemoteInvokeContext context); 18 | 19 | /// 20 | /// 调用。 21 | /// 22 | /// 调用上下文。 23 | /// 取消操作通知实例。 24 | /// 远程调用结果消息模型。 25 | Task InvokeAsync(RemoteInvokeContext context, CancellationToken cancellationToken); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/Implementation/RemoteInvokeService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Rabbit.Rpc.Exceptions; 3 | using Rabbit.Rpc.Messages; 4 | using Rabbit.Rpc.Runtime.Client.Address.Resolvers; 5 | using Rabbit.Rpc.Runtime.Client.HealthChecks; 6 | using Rabbit.Rpc.Transport; 7 | using System; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace Rabbit.Rpc.Runtime.Client.Implementation 12 | { 13 | public class RemoteInvokeService : IRemoteInvokeService 14 | { 15 | private readonly IAddressResolver _addressResolver; 16 | private readonly ITransportClientFactory _transportClientFactory; 17 | private readonly ILogger _logger; 18 | private readonly IHealthCheckService _healthCheckService; 19 | 20 | public RemoteInvokeService(IAddressResolver addressResolver, ITransportClientFactory transportClientFactory, ILogger logger, IHealthCheckService healthCheckService) 21 | { 22 | _addressResolver = addressResolver; 23 | _transportClientFactory = transportClientFactory; 24 | _logger = logger; 25 | _healthCheckService = healthCheckService; 26 | } 27 | 28 | #region Implementation of IRemoteInvokeService 29 | 30 | public Task InvokeAsync(RemoteInvokeContext context) 31 | { 32 | return InvokeAsync(context, Task.Factory.CancellationToken); 33 | } 34 | 35 | public async Task InvokeAsync(RemoteInvokeContext context, CancellationToken cancellationToken) 36 | { 37 | if (context == null) 38 | throw new ArgumentNullException(nameof(context)); 39 | 40 | if (context.InvokeMessage == null) 41 | throw new ArgumentNullException(nameof(context.InvokeMessage)); 42 | 43 | if (string.IsNullOrEmpty(context.InvokeMessage.ServiceId)) 44 | throw new ArgumentException("服务Id不能为空。", nameof(context.InvokeMessage.ServiceId)); 45 | 46 | var invokeMessage = context.InvokeMessage; 47 | var address = await _addressResolver.Resolver(invokeMessage.ServiceId); 48 | 49 | if (address == null) 50 | throw new RpcException($"无法解析服务Id:{invokeMessage.ServiceId}的地址信息。"); 51 | 52 | try 53 | { 54 | var endPoint = address.CreateEndPoint(); 55 | 56 | if (_logger.IsEnabled(LogLevel.Debug)) 57 | _logger.LogDebug($"使用地址:'{endPoint}'进行调用。"); 58 | 59 | var client = _transportClientFactory.CreateClient(endPoint); 60 | return await client.SendAsync(context.InvokeMessage); 61 | } 62 | catch (RpcCommunicationException) 63 | { 64 | await _healthCheckService.MarkFailure(address); 65 | throw; 66 | } 67 | catch (Exception exception) 68 | { 69 | _logger.LogError($"发起请求中发生了错误,服务Id:{invokeMessage.ServiceId}。", exception); 70 | throw; 71 | } 72 | } 73 | 74 | #endregion Implementation of IRemoteInvokeService 75 | } 76 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Client/RemoteInvokeContext.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | 3 | namespace Rabbit.Rpc.Runtime.Client 4 | { 5 | /// 6 | /// 远程调用上下文。 7 | /// 8 | public class RemoteInvokeContext 9 | { 10 | /// 11 | /// 远程调用消息。 12 | /// 13 | public RemoteInvokeMessage InvokeMessage { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/IServiceEntryLocate.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server 4 | { 5 | /// 6 | /// 一个抽象的服务条目定位器。 7 | /// 8 | public interface IServiceEntryLocate 9 | { 10 | /// 11 | /// 定位服务条目。 12 | /// 13 | /// 远程调用消息。 14 | /// 服务条目。 15 | ServiceEntry Locate(RemoteInvokeMessage invokeMessage); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/IServiceEntryManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server 4 | { 5 | /// 6 | /// 一个抽象的服务条目管理者。 7 | /// 8 | public interface IServiceEntryManager 9 | { 10 | /// 11 | /// 获取服务条目集合。 12 | /// 13 | /// 服务条目集合。 14 | IEnumerable GetEntries(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/IServiceEntryProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server 4 | { 5 | /// 6 | /// 一个抽象的服务条目提供程序。 7 | /// 8 | public interface IServiceEntryProvider 9 | { 10 | /// 11 | /// 获取服务条目集合。 12 | /// 13 | /// 服务条目集合。 14 | IEnumerable GetEntries(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/IServiceExecutor.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using Rabbit.Rpc.Transport; 3 | using System.Threading.Tasks; 4 | 5 | namespace Rabbit.Rpc.Runtime.Server 6 | { 7 | /// 8 | /// 一个抽象的服务执行器。 9 | /// 10 | public interface IServiceExecutor 11 | { 12 | /// 13 | /// 执行。 14 | /// 15 | /// 消息发送者。 16 | /// 调用消息。 17 | Task ExecuteAsync(IMessageSender sender,TransportMessage message); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/IServiceHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Threading.Tasks; 4 | 5 | namespace Rabbit.Rpc.Runtime.Server 6 | { 7 | /// 8 | /// 一个抽象的服务主机。 9 | /// 10 | public interface IServiceHost : IDisposable 11 | { 12 | /// 13 | /// 启动主机。 14 | /// 15 | /// 主机终结点。 16 | /// 一个任务。 17 | Task StartAsync(EndPoint endPoint); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/DefaultServiceEntryLocate.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Linq; 3 | 4 | namespace Rabbit.Rpc.Runtime.Server.Implementation 5 | { 6 | /// 7 | /// 默认的服务条目定位器。 8 | /// 9 | public class DefaultServiceEntryLocate : IServiceEntryLocate 10 | { 11 | private readonly IServiceEntryManager _serviceEntryManager; 12 | 13 | public DefaultServiceEntryLocate(IServiceEntryManager serviceEntryManager) 14 | { 15 | _serviceEntryManager = serviceEntryManager; 16 | } 17 | 18 | #region Implementation of IServiceEntryLocate 19 | 20 | /// 21 | /// 定位服务条目。 22 | /// 23 | /// 远程调用消息。 24 | /// 服务条目。 25 | public ServiceEntry Locate(RemoteInvokeMessage invokeMessage) 26 | { 27 | var serviceEntries = _serviceEntryManager.GetEntries(); 28 | return serviceEntries.SingleOrDefault(i => i.Descriptor.Id == invokeMessage.ServiceId); 29 | } 30 | 31 | #endregion Implementation of IServiceEntryLocate 32 | } 33 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/DefaultServiceEntryManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Rabbit.Rpc.Runtime.Server.Implementation 6 | { 7 | /// 8 | /// 默认的服务条目管理者。 9 | /// 10 | public class DefaultServiceEntryManager : IServiceEntryManager 11 | { 12 | #region Field 13 | 14 | private readonly IEnumerable _serviceEntries; 15 | 16 | #endregion Field 17 | 18 | #region Constructor 19 | 20 | public DefaultServiceEntryManager(IEnumerable providers) 21 | { 22 | var list = new List(); 23 | foreach (var provider in providers) 24 | { 25 | var entries = provider.GetEntries().ToArray(); 26 | foreach (var entry in entries) 27 | { 28 | if (list.Any(i => i.Descriptor.Id == entry.Descriptor.Id)) 29 | throw new InvalidOperationException($"本地包含多个Id为:{entry.Descriptor.Id} 的服务条目。"); 30 | } 31 | list.AddRange(entries); 32 | } 33 | _serviceEntries = list.ToArray(); 34 | } 35 | 36 | #endregion Constructor 37 | 38 | #region Implementation of IServiceEntryManager 39 | 40 | /// 41 | /// 获取服务条目集合。 42 | /// 43 | /// 服务条目集合。 44 | public IEnumerable GetEntries() 45 | { 46 | return _serviceEntries; 47 | } 48 | 49 | #endregion Implementation of IServiceEntryManager 50 | } 51 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/DefaultServiceExecutor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Rabbit.Rpc.Messages; 3 | using Rabbit.Rpc.Transport; 4 | using System; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | 8 | namespace Rabbit.Rpc.Runtime.Server.Implementation 9 | { 10 | public class DefaultServiceExecutor : IServiceExecutor 11 | { 12 | #region Field 13 | 14 | private readonly IServiceEntryLocate _serviceEntryLocate; 15 | private readonly ILogger _logger; 16 | 17 | #endregion Field 18 | 19 | #region Constructor 20 | 21 | public DefaultServiceExecutor(IServiceEntryLocate serviceEntryLocate, ILogger logger) 22 | { 23 | _serviceEntryLocate = serviceEntryLocate; 24 | _logger = logger; 25 | } 26 | 27 | #endregion Constructor 28 | 29 | #region Implementation of IServiceExecutor 30 | 31 | /// 32 | /// 执行。 33 | /// 34 | /// 消息发送者。 35 | /// 调用消息。 36 | public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) 37 | { 38 | if (_logger.IsEnabled(LogLevel.Information)) 39 | _logger.LogInformation("接收到消息。"); 40 | 41 | if (!message.IsInvokeMessage()) 42 | return; 43 | 44 | RemoteInvokeMessage remoteInvokeMessage; 45 | try 46 | { 47 | remoteInvokeMessage = message.GetContent(); 48 | } 49 | catch (Exception exception) 50 | { 51 | _logger.LogError("将接收到的消息反序列化成 TransportMessage 时发送了错误。", exception); 52 | return; 53 | } 54 | 55 | var entry = _serviceEntryLocate.Locate(remoteInvokeMessage); 56 | 57 | if (entry == null) 58 | { 59 | if (_logger.IsEnabled(LogLevel.Error)) 60 | _logger.LogError($"根据服务Id:{remoteInvokeMessage.ServiceId},找不到服务条目。"); 61 | return; 62 | } 63 | 64 | if (_logger.IsEnabled(LogLevel.Debug)) 65 | _logger.LogDebug("准备执行本地逻辑。"); 66 | 67 | var resultMessage = new RemoteInvokeResultMessage(); 68 | 69 | //是否需要等待执行。 70 | if (entry.Descriptor.WaitExecution()) 71 | { 72 | //执行本地代码。 73 | await LocalExecuteAsync(entry, remoteInvokeMessage, resultMessage); 74 | //向客户端发送调用结果。 75 | await SendRemoteInvokeResult(sender, message.Id, resultMessage); 76 | } 77 | else 78 | { 79 | //通知客户端已接收到消息。 80 | await SendRemoteInvokeResult(sender, message.Id, resultMessage); 81 | //确保新起一个线程执行,不堵塞当前线程。 82 | await Task.Factory.StartNew(async () => 83 | { 84 | //执行本地代码。 85 | await LocalExecuteAsync(entry, remoteInvokeMessage, resultMessage); 86 | }, TaskCreationOptions.LongRunning); 87 | } 88 | } 89 | 90 | #endregion Implementation of IServiceExecutor 91 | 92 | #region Private Method 93 | 94 | private async Task LocalExecuteAsync(ServiceEntry entry, RemoteInvokeMessage remoteInvokeMessage, RemoteInvokeResultMessage resultMessage) 95 | { 96 | try 97 | { 98 | var result = await entry.Func(remoteInvokeMessage.Parameters); 99 | var task = result as Task; 100 | 101 | if (task == null) 102 | { 103 | resultMessage.Result = result; 104 | } 105 | else 106 | { 107 | task.Wait(); 108 | 109 | var taskType = task.GetType().GetTypeInfo(); 110 | if (taskType.IsGenericType) 111 | resultMessage.Result = taskType.GetProperty("Result").GetValue(task); 112 | } 113 | } 114 | catch (Exception exception) 115 | { 116 | if (_logger.IsEnabled(LogLevel.Error)) 117 | _logger.LogError("执行本地逻辑时候发生了错误。", exception); 118 | resultMessage.ExceptionMessage = GetExceptionMessage(exception); 119 | } 120 | } 121 | 122 | private async Task SendRemoteInvokeResult(IMessageSender sender, string messageId, RemoteInvokeResultMessage resultMessage) 123 | { 124 | try 125 | { 126 | if (_logger.IsEnabled(LogLevel.Debug)) 127 | _logger.LogDebug("准备发送响应消息。"); 128 | 129 | await sender.SendAndFlushAsync(TransportMessage.CreateInvokeResultMessage(messageId, resultMessage)); 130 | if (_logger.IsEnabled(LogLevel.Debug)) 131 | _logger.LogDebug("响应消息发送成功。"); 132 | } 133 | catch (Exception exception) 134 | { 135 | if (_logger.IsEnabled(LogLevel.Error)) 136 | _logger.LogError("发送响应消息时候发生了异常。", exception); 137 | } 138 | } 139 | 140 | private static string GetExceptionMessage(Exception exception) 141 | { 142 | if (exception == null) 143 | return string.Empty; 144 | 145 | var message = exception.Message; 146 | if (exception.InnerException != null) 147 | { 148 | message += "|InnerException:" + GetExceptionMessage(exception.InnerException); 149 | } 150 | return message; 151 | } 152 | 153 | #endregion Private Method 154 | } 155 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/DefaultServiceHost.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Transport; 2 | using System; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace Rabbit.Rpc.Runtime.Server.Implementation 7 | { 8 | /// 9 | /// 一个默认的服务主机。 10 | /// 11 | public class DefaultServiceHost : ServiceHostAbstract 12 | { 13 | #region Field 14 | 15 | private readonly Func> _messageListenerFactory; 16 | private IMessageListener _serverMessageListener; 17 | 18 | #endregion Field 19 | 20 | public DefaultServiceHost(Func> messageListenerFactory, IServiceExecutor serviceExecutor) : base(serviceExecutor) 21 | { 22 | _messageListenerFactory = messageListenerFactory; 23 | } 24 | 25 | #region Overrides of ServiceHostAbstract 26 | 27 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 28 | public override void Dispose() 29 | { 30 | (_serverMessageListener as IDisposable)?.Dispose(); 31 | } 32 | 33 | /// 34 | /// 启动主机。 35 | /// 36 | /// 主机终结点。 37 | /// 一个任务。 38 | public override async Task StartAsync(EndPoint endPoint) 39 | { 40 | if (_serverMessageListener != null) 41 | return; 42 | _serverMessageListener = await _messageListenerFactory(endPoint); 43 | _serverMessageListener.Received += async (sender, message) => 44 | { 45 | await Task.Run(() => 46 | { 47 | MessageListener.OnReceived(sender, message); 48 | }); 49 | }; 50 | } 51 | 52 | #endregion Overrides of ServiceHostAbstract 53 | } 54 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Attributes/AttributeServiceEntryProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery.Attributes 8 | { 9 | /// 10 | /// Service标记类型的服务条目提供程序。 11 | /// 12 | public class AttributeServiceEntryProvider : IServiceEntryProvider 13 | { 14 | #region Field 15 | 16 | private readonly IEnumerable _types; 17 | private readonly IClrServiceEntryFactory _clrServiceEntryFactory; 18 | private readonly ILogger _logger; 19 | 20 | #endregion Field 21 | 22 | #region Constructor 23 | 24 | public AttributeServiceEntryProvider(IEnumerable types, IClrServiceEntryFactory clrServiceEntryFactory, ILogger logger) 25 | { 26 | _types = types; 27 | _clrServiceEntryFactory = clrServiceEntryFactory; 28 | _logger = logger; 29 | } 30 | 31 | #endregion Constructor 32 | 33 | #region Implementation of IServiceEntryProvider 34 | 35 | /// 36 | /// 获取服务条目集合。 37 | /// 38 | /// 服务条目集合。 39 | public IEnumerable GetEntries() 40 | { 41 | var services = _types.Where(i => 42 | { 43 | var typeInfo = i.GetTypeInfo(); 44 | return typeInfo.IsInterface && typeInfo.GetCustomAttribute() != null; 45 | }).ToArray(); 46 | var serviceImplementations = _types.Where(i => 47 | { 48 | var typeInfo = i.GetTypeInfo(); 49 | return typeInfo.IsClass && !typeInfo.IsAbstract && i.Namespace != null && !i.Namespace.StartsWith("System") && 50 | !i.Namespace.StartsWith("Microsoft"); 51 | }).ToArray(); 52 | 53 | if (_logger.IsEnabled(LogLevel.Information)) 54 | { 55 | _logger.LogInformation($"发现了以下服务:{string.Join(",", services.Select(i => i.ToString()))}。"); 56 | } 57 | 58 | var entries = new List(); 59 | foreach (var service in services) 60 | { 61 | foreach (var serviceImplementation in serviceImplementations.Where(i => service.GetTypeInfo().IsAssignableFrom(i))) 62 | { 63 | entries.AddRange(_clrServiceEntryFactory.CreateServiceEntry(service, serviceImplementation)); 64 | } 65 | } 66 | return entries; 67 | } 68 | 69 | #endregion Implementation of IServiceEntryProvider 70 | } 71 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Attributes/RpcServiceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery.Attributes 4 | { 5 | /// 6 | /// 服务标记。 7 | /// 8 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 9 | public class RpcServiceAttribute : RpcServiceDescriptorAttribute 10 | { 11 | /// 12 | /// 初始化一个新的Rpc服务标记。 13 | /// 14 | public RpcServiceAttribute() 15 | { 16 | IsWaitExecution = true; 17 | } 18 | 19 | /// 20 | /// 是否需要等待服务执行。 21 | /// 22 | public bool IsWaitExecution { get; set; } 23 | 24 | #region Overrides of RpcServiceDescriptorAttribute 25 | 26 | /// 27 | /// 应用标记。 28 | /// 29 | /// 服务描述符。 30 | public override void Apply(ServiceDescriptor descriptor) 31 | { 32 | descriptor.WaitExecution(IsWaitExecution); 33 | } 34 | 35 | #endregion Overrides of RpcServiceDescriptorAttribute 36 | } 37 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Attributes/RpcServiceBundleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery.Attributes 4 | { 5 | /// 6 | /// 服务集标记。 7 | /// 8 | [AttributeUsage(AttributeTargets.Interface)] 9 | public class RpcServiceBundleAttribute : Attribute 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Attributes/RpcServiceDescriptorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery.Attributes 4 | { 5 | /// 6 | /// Rpc服务描述符标记。 7 | /// 8 | public abstract class RpcServiceDescriptorAttribute : Attribute 9 | { 10 | /// 11 | /// 应用标记。 12 | /// 13 | /// 服务描述符。 14 | public abstract void Apply(ServiceDescriptor descriptor); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Attributes/RpcServiceMetadataAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery.Attributes 4 | { 5 | /// 6 | /// Rpc服务元数据标记。 7 | /// 8 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] 9 | public class RpcServiceMetadataAttribute : RpcServiceDescriptorAttribute 10 | { 11 | /// 12 | /// 初始化一个新的Rpc服务元数据标记。 13 | /// 14 | /// 名称。 15 | /// 数据。 16 | public RpcServiceMetadataAttribute(string name, object data) 17 | { 18 | Name = name; 19 | Data = data; 20 | } 21 | 22 | /// 23 | /// 名称。 24 | /// 25 | public string Name { get; } 26 | 27 | /// 28 | /// 数据。 29 | /// 30 | public object Data { get; } 31 | 32 | #region Overrides of RpcServiceDescriptorAttribute 33 | 34 | /// 35 | /// 应用标记。 36 | /// 37 | /// 服务描述符。 38 | public override void Apply(ServiceDescriptor descriptor) 39 | { 40 | descriptor.Metadatas[Name] = Data; 41 | } 42 | 43 | #endregion Overrides of RpcServiceDescriptorAttribute 44 | } 45 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/IClrServiceEntryFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Rabbit.Rpc.Runtime.Server.Implementation.ServiceDiscovery 5 | { 6 | /// 7 | /// 一个抽象的Clr服务条目工厂。 8 | /// 9 | public interface IClrServiceEntryFactory 10 | { 11 | /// 12 | /// 创建服务条目。 13 | /// 14 | /// 服务类型。 15 | /// 服务实现类型。 16 | /// 服务条目集合。 17 | IEnumerable CreateServiceEntry(Type service, Type serviceImplementation); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RabbitTeam/RabbitCloud/8d42a11d1208f55117a411b4248a5abf336161e6/src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/Implementation/ServiceHostAbstract.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using Rabbit.Rpc.Transport; 3 | using Rabbit.Rpc.Transport.Implementation; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | 7 | namespace Rabbit.Rpc.Runtime.Server.Implementation 8 | { 9 | /// 10 | /// 服务主机基类。 11 | /// 12 | public abstract class ServiceHostAbstract : IServiceHost 13 | { 14 | #region Field 15 | 16 | private readonly IServiceExecutor _serviceExecutor; 17 | 18 | /// 19 | /// 消息监听者。 20 | /// 21 | protected IMessageListener MessageListener { get; } = new MessageListener(); 22 | 23 | #endregion Field 24 | 25 | #region Constructor 26 | 27 | protected ServiceHostAbstract(IServiceExecutor serviceExecutor) 28 | { 29 | _serviceExecutor = serviceExecutor; 30 | MessageListener.Received += MessageListener_Received; 31 | } 32 | 33 | #endregion Constructor 34 | 35 | #region Implementation of IDisposable 36 | 37 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 38 | public abstract void Dispose(); 39 | 40 | #endregion Implementation of IDisposable 41 | 42 | #region Implementation of IServiceHost 43 | 44 | /// 45 | /// 启动主机。 46 | /// 47 | /// 主机终结点。 48 | /// 一个任务。 49 | public abstract Task StartAsync(EndPoint endPoint); 50 | 51 | #endregion Implementation of IServiceHost 52 | 53 | #region Private Method 54 | 55 | private async Task MessageListener_Received(IMessageSender sender, TransportMessage message) 56 | { 57 | await _serviceExecutor.ExecuteAsync(sender, message); 58 | } 59 | 60 | #endregion Private Method 61 | } 62 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Runtime/Server/ServiceEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace Rabbit.Rpc.Runtime.Server 6 | { 7 | /// 8 | /// 服务条目。 9 | /// 10 | public class ServiceEntry 11 | { 12 | /// 13 | /// 执行委托。 14 | /// 15 | public Func, Task> Func { get; set; } 16 | 17 | /// 18 | /// 服务描述符。 19 | /// 20 | public ServiceDescriptor Descriptor { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Serialization/ISerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Serialization 4 | { 5 | /// 6 | /// 一个抽象的序列化器。 7 | /// 8 | /// 序列化内容类型。 9 | public interface ISerializer 10 | { 11 | /// 12 | /// 序列化。 13 | /// 14 | /// 需要序列化的对象。 15 | /// 序列化之后的结果。 16 | T Serialize(object instance); 17 | 18 | /// 19 | /// 反序列化。 20 | /// 21 | /// 序列化的内容。 22 | /// 对象类型。 23 | /// 一个对象实例。 24 | object Deserialize(T content, Type type); 25 | } 26 | 27 | /// 28 | /// 序列化器扩展方法。 29 | /// 30 | public static class SerializerExtensions 31 | { 32 | /// 33 | /// 反序列化。 34 | /// 35 | /// 序列化内容类型。 36 | /// 对象类型。 37 | /// 序列化器。 38 | /// 序列化的内容。 39 | /// 一个对象实例。 40 | public static TResult Deserialize(this ISerializer serializer, T content) 41 | { 42 | return (TResult)serializer.Deserialize(content, typeof(TResult)); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Serialization/Implementation/JsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace Rabbit.Rpc.Serialization.Implementation 5 | { 6 | /// 7 | /// Json序列化器。 8 | /// 9 | public sealed class JsonSerializer : ISerializer 10 | { 11 | #region Implementation of ISerializer 12 | 13 | /// 14 | /// 序列化。 15 | /// 16 | /// 需要序列化的对象。 17 | /// 序列化之后的结果。 18 | public string Serialize(object instance) 19 | { 20 | return JsonConvert.SerializeObject(instance); 21 | } 22 | 23 | /// 24 | /// 反序列化。 25 | /// 26 | /// 序列化的内容。 27 | /// 对象类型。 28 | /// 一个对象实例。 29 | public object Deserialize(string content, Type type) 30 | { 31 | return JsonConvert.DeserializeObject(content, type); 32 | } 33 | 34 | #endregion Implementation of ISerializer 35 | } 36 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Serialization/Implementation/StringByteArraySerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Rabbit.Rpc.Serialization.Implementation 5 | { 6 | /// 7 | /// 基于string类型的byte[]序列化器。 8 | /// 9 | public class StringByteArraySerializer : ISerializer 10 | { 11 | #region Field 12 | 13 | private readonly ISerializer _serializer; 14 | 15 | #endregion Field 16 | 17 | #region Constructor 18 | 19 | public StringByteArraySerializer(ISerializer serializer) 20 | { 21 | _serializer = serializer; 22 | } 23 | 24 | #endregion Constructor 25 | 26 | #region Implementation of ISerializer 27 | 28 | /// 29 | /// 序列化。 30 | /// 31 | /// 需要序列化的对象。 32 | /// 序列化之后的结果。 33 | public byte[] Serialize(object instance) 34 | { 35 | return Encoding.UTF8.GetBytes(_serializer.Serialize(instance)); 36 | } 37 | 38 | /// 39 | /// 反序列化。 40 | /// 41 | /// 序列化的内容。 42 | /// 对象类型。 43 | /// 一个对象实例。 44 | public object Deserialize(byte[] content, Type type) 45 | { 46 | return _serializer.Deserialize(Encoding.UTF8.GetString(content), type); 47 | } 48 | 49 | #endregion Implementation of ISerializer 50 | } 51 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Serialization/Implementation/StringObjectSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Rabbit.Rpc.Serialization.Implementation 4 | { 5 | /// 6 | /// 基于string类型的object序列化器。 7 | /// 8 | public class StringObjectSerializer : ISerializer 9 | { 10 | #region Field 11 | 12 | private readonly ISerializer _serializer; 13 | 14 | #endregion Field 15 | 16 | #region Constructor 17 | 18 | public StringObjectSerializer(ISerializer serializer) 19 | { 20 | _serializer = serializer; 21 | } 22 | 23 | #endregion Constructor 24 | 25 | #region Implementation of ISerializer 26 | 27 | /// 28 | /// 序列化。 29 | /// 30 | /// 需要序列化的对象。 31 | /// 序列化之后的结果。 32 | public object Serialize(object instance) 33 | { 34 | return _serializer.Serialize(instance); 35 | } 36 | 37 | /// 38 | /// 反序列化。 39 | /// 40 | /// 序列化的内容。 41 | /// 对象类型。 42 | /// 一个对象实例。 43 | public object Deserialize(object content, Type type) 44 | { 45 | return _serializer.Deserialize(content.ToString(), type); 46 | } 47 | 48 | #endregion Implementation of ISerializer 49 | } 50 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/ServiceDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Rabbit.Rpc 6 | { 7 | /// 8 | /// 服务描述符扩展方法。 9 | /// 10 | public static class ServiceDescriptorExtensions 11 | { 12 | /// 13 | /// 获取组名称。 14 | /// 15 | /// 服务描述符。 16 | /// 组名称。 17 | public static string GroupName(this ServiceDescriptor descriptor) 18 | { 19 | return descriptor.GetMetadata("GroupName"); 20 | } 21 | 22 | /// 23 | /// 设置组名称。 24 | /// 25 | /// 服务描述符。 26 | /// 组名称。 27 | /// 服务描述符。 28 | public static ServiceDescriptor GroupName(this ServiceDescriptor descriptor, string groupName) 29 | { 30 | descriptor.Metadatas["GroupName"] = groupName; 31 | 32 | return descriptor; 33 | } 34 | 35 | /// 36 | /// 设置是否等待执行。 37 | /// 38 | /// 服务描述符。 39 | /// 如果需要等待执行则为true,否则为false,默认为true。 40 | /// 41 | public static ServiceDescriptor WaitExecution(this ServiceDescriptor descriptor, bool waitExecution) 42 | { 43 | descriptor.Metadatas["WaitExecution"] = waitExecution; 44 | return descriptor; 45 | } 46 | 47 | /// 48 | /// 获取释放等待执行的设置。 49 | /// 50 | /// 服务描述符。 51 | /// 如果需要等待执行则为true,否则为false,默认为true。 52 | public static bool WaitExecution(this ServiceDescriptor descriptor) 53 | { 54 | return descriptor.GetMetadata("WaitExecution", true); 55 | } 56 | } 57 | 58 | /// 59 | /// 服务描述符。 60 | /// 61 | public class ServiceDescriptor 62 | { 63 | /// 64 | /// 初始化一个新的服务描述符。 65 | /// 66 | public ServiceDescriptor() 67 | { 68 | Metadatas = new Dictionary(StringComparer.OrdinalIgnoreCase); 69 | } 70 | 71 | /// 72 | /// 服务Id。 73 | /// 74 | public string Id { get; set; } 75 | 76 | /// 77 | /// 元数据。 78 | /// 79 | public IDictionary Metadatas { get; set; } 80 | 81 | /// 82 | /// 获取一个元数据。 83 | /// 84 | /// 元数据类型。 85 | /// 元数据名称。 86 | /// 如果指定名称的元数据不存在则返回这个参数。 87 | /// 元数据值。 88 | public T GetMetadata(string name, T def = default(T)) 89 | { 90 | if (!Metadatas.ContainsKey(name)) 91 | return def; 92 | 93 | return (T)Metadatas[name]; 94 | } 95 | 96 | #region Equality members 97 | 98 | /// Determines whether the specified object is equal to the current object. 99 | /// true if the specified object is equal to the current object; otherwise, false. 100 | /// The object to compare with the current object. 101 | public override bool Equals(object obj) 102 | { 103 | var model = obj as ServiceDescriptor; 104 | if (model == null) 105 | return false; 106 | 107 | if (obj.GetType() != GetType()) 108 | return false; 109 | 110 | if (model.Id != Id) 111 | return false; 112 | 113 | return model.Metadatas.Count == Metadatas.Count && model.Metadatas.All(metadata => 114 | { 115 | object value; 116 | if (!Metadatas.TryGetValue(metadata.Key, out value)) 117 | return false; 118 | 119 | if (metadata.Value == null && value == null) 120 | return true; 121 | if (metadata.Value == null || value == null) 122 | return false; 123 | 124 | return metadata.Value.Equals(value); 125 | }); 126 | } 127 | 128 | /// Serves as the default hash function. 129 | /// A hash code for the current object. 130 | public override int GetHashCode() 131 | { 132 | return ToString().GetHashCode(); 133 | } 134 | 135 | public static bool operator ==(ServiceDescriptor model1, ServiceDescriptor model2) 136 | { 137 | return Equals(model1, model2); 138 | } 139 | 140 | public static bool operator !=(ServiceDescriptor model1, ServiceDescriptor model2) 141 | { 142 | return !Equals(model1, model2); 143 | } 144 | 145 | #endregion Equality members 146 | } 147 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/ITransportMessageCodecFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Rabbit.Rpc.Transport.Codec 2 | { 3 | /// 4 | /// 一个抽象的传输消息编解码器工厂。 5 | /// 6 | public interface ITransportMessageCodecFactory 7 | { 8 | /// 9 | /// 获取编码器。 10 | /// 11 | /// 编码器实例。 12 | ITransportMessageEncoder GetEncoder(); 13 | 14 | /// 15 | /// 获取解码器。 16 | /// 17 | /// 解码器实例。 18 | ITransportMessageDecoder GetDecoder(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/ITransportMessageDecoder.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | 3 | namespace Rabbit.Rpc.Transport.Codec 4 | { 5 | public interface ITransportMessageDecoder 6 | { 7 | TransportMessage Decode(byte[] data); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/ITransportMessageEncoder.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | 3 | namespace Rabbit.Rpc.Transport.Codec 4 | { 5 | public interface ITransportMessageEncoder 6 | { 7 | byte[] Encode(TransportMessage message); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/Implementation/JsonTransportMessageCodecFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Rabbit.Rpc.Transport.Codec.Implementation 2 | { 3 | public class JsonTransportMessageCodecFactory : ITransportMessageCodecFactory 4 | { 5 | #region Field 6 | 7 | private readonly ITransportMessageEncoder _transportMessageEncoder = new JsonTransportMessageEncoder(); 8 | private readonly ITransportMessageDecoder _transportMessageDecoder = new JsonTransportMessageDecoder(); 9 | 10 | #endregion Field 11 | 12 | #region Implementation of ITransportMessageCodecFactory 13 | 14 | /// 15 | /// 获取编码器。 16 | /// 17 | /// 编码器实例。 18 | public ITransportMessageEncoder GetEncoder() 19 | { 20 | return _transportMessageEncoder; 21 | } 22 | 23 | /// 24 | /// 获取解码器。 25 | /// 26 | /// 解码器实例。 27 | public ITransportMessageDecoder GetDecoder() 28 | { 29 | return _transportMessageDecoder; 30 | } 31 | 32 | #endregion Implementation of ITransportMessageCodecFactory 33 | } 34 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/Implementation/JsonTransportMessageDecoder.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Rabbit.Rpc.Messages; 3 | using System.Text; 4 | 5 | namespace Rabbit.Rpc.Transport.Codec.Implementation 6 | { 7 | public sealed class JsonTransportMessageDecoder : ITransportMessageDecoder 8 | { 9 | #region Implementation of ITransportMessageDecoder 10 | 11 | public TransportMessage Decode(byte[] data) 12 | { 13 | var content = Encoding.UTF8.GetString(data); 14 | var message = JsonConvert.DeserializeObject(content); 15 | if (message.IsInvokeMessage()) 16 | { 17 | message.Content = JsonConvert.DeserializeObject(message.Content.ToString()); 18 | } 19 | if (message.IsInvokeResultMessage()) 20 | { 21 | message.Content = JsonConvert.DeserializeObject(message.Content.ToString()); 22 | } 23 | return message; 24 | } 25 | 26 | #endregion Implementation of ITransportMessageDecoder 27 | } 28 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Codec/Implementation/JsonTransportMessageEncoder.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Rabbit.Rpc.Messages; 3 | using System.Text; 4 | 5 | namespace Rabbit.Rpc.Transport.Codec.Implementation 6 | { 7 | public sealed class JsonTransportMessageEncoder : ITransportMessageEncoder 8 | { 9 | #region Implementation of ITransportMessageEncoder 10 | 11 | public byte[] Encode(TransportMessage message) 12 | { 13 | var content = JsonConvert.SerializeObject(message); 14 | return Encoding.UTF8.GetBytes(content); 15 | } 16 | 17 | #endregion Implementation of ITransportMessageEncoder 18 | } 19 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/IMessageListener.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Transport 5 | { 6 | /// 7 | /// 接受到消息的委托。 8 | /// 9 | /// 消息发送者。 10 | /// 接收到的消息。 11 | public delegate Task ReceivedDelegate(IMessageSender sender, TransportMessage message); 12 | 13 | /// 14 | /// 一个抽象的消息监听者。 15 | /// 16 | public interface IMessageListener 17 | { 18 | /// 19 | /// 接收到消息的事件。 20 | /// 21 | event ReceivedDelegate Received; 22 | 23 | /// 24 | /// 触发接收到消息事件。 25 | /// 26 | /// 消息发送者。 27 | /// 接收到的消息。 28 | /// 一个任务。 29 | Task OnReceived(IMessageSender sender, TransportMessage message); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/IMessageSender.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Transport 5 | { 6 | /// 7 | /// 一个抽象的发送者。 8 | /// 9 | public interface IMessageSender 10 | { 11 | /// 12 | /// 发送消息。 13 | /// 14 | /// 消息内容。 15 | /// 一个任务。 16 | Task SendAsync(TransportMessage message); 17 | 18 | /// 19 | /// 发送消息并清空缓冲区。 20 | /// 21 | /// 消息内容。 22 | /// 一个任务。 23 | Task SendAndFlushAsync(TransportMessage message); 24 | } 25 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/ITransportClient.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Transport 5 | { 6 | /// 7 | /// 一个抽象的传输客户端。 8 | /// 9 | public interface ITransportClient 10 | { 11 | /// 12 | /// 发送消息。 13 | /// 14 | /// 远程调用消息模型。 15 | /// 远程调用消息的传输消息。 16 | Task SendAsync(RemoteInvokeMessage message); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/ITransportClientFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Rabbit.Rpc.Transport 4 | { 5 | /// 6 | /// 一个抽象的传输客户端工厂。 7 | /// 8 | public interface ITransportClientFactory 9 | { 10 | /// 11 | /// 创建客户端。 12 | /// 13 | /// 终结点。 14 | /// 传输客户端实例。 15 | ITransportClient CreateClient(EndPoint endPoint); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Rabbit.Rpc/Transport/Implementation/MessageListener.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Messages; 2 | using System.Threading.Tasks; 3 | 4 | namespace Rabbit.Rpc.Transport.Implementation 5 | { 6 | /// 7 | /// 消息监听者。 8 | /// 9 | public class MessageListener : IMessageListener 10 | { 11 | #region Implementation of IMessageListener 12 | 13 | /// 14 | /// 接收到消息的事件。 15 | /// 16 | public event ReceivedDelegate Received; 17 | 18 | /// 19 | /// 触发接收到消息事件。 20 | /// 21 | /// 消息发送者。 22 | /// 接收到的消息。 23 | /// 一个任务。 24 | public async Task OnReceived(IMessageSender sender, TransportMessage message) 25 | { 26 | if (Received == null) 27 | return; 28 | await Received(sender, message); 29 | } 30 | 31 | #endregion Implementation of IMessageListener 32 | } 33 | } -------------------------------------------------------------------------------- /src/examples/Echo.Client/Echo.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | Echo.Client 6 | Exe 7 | Echo.Client 8 | 1.0.3 9 | $(PackageTargetFallback);dnxcore50 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/examples/Echo.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Exceptions; 6 | using Rabbit.Rpc.ProxyGenerator; 7 | using System; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using Rabbit.Transport.DotNetty; 13 | 14 | namespace Echo.Client 15 | { 16 | public class Program 17 | { 18 | public static void Main(string[] args) 19 | { 20 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 21 | 22 | var serviceCollection = new ServiceCollection(); 23 | 24 | serviceCollection 25 | .AddLogging() 26 | .AddClient() 27 | .UseSharedFileRouteManager(@"d:\routes.txt") 28 | .UseDotNettyTransport(); 29 | 30 | var serviceProvider = serviceCollection.BuildServiceProvider(); 31 | 32 | serviceProvider.GetRequiredService() 33 | .AddConsole((c, l) => (int)l >= 3); 34 | 35 | var serviceProxyGenerater = serviceProvider.GetRequiredService(); 36 | var serviceProxyFactory = serviceProvider.GetRequiredService(); 37 | var services = serviceProxyGenerater.GenerateProxys(new[] { typeof(IUserService) }).ToArray(); 38 | 39 | //创建IUserService的代理。 40 | var userService = serviceProxyFactory.CreateProxy(services.Single(typeof(IUserService).GetTypeInfo().IsAssignableFrom)); 41 | 42 | var logger = serviceProvider.GetRequiredService>(); 43 | while (true) 44 | { 45 | Task.Run(async () => 46 | { 47 | try 48 | { 49 | Console.WriteLine($"userService.GetUserName:{await userService.GetUserName(1)}"); 50 | Console.WriteLine($"userService.GetUserId:{await userService.GetUserId("rabbit")}"); 51 | Console.WriteLine( 52 | $"userService.GetUserLastSignInTime:{await userService.GetUserLastSignInTime(1)}"); 53 | Console.WriteLine($"userService.Exists:{await userService.Exists(1)}"); 54 | var user = await userService.GetUser(1); 55 | Console.WriteLine($"userService.GetUser:name={user.Name},age={user.Age}"); 56 | Console.WriteLine($"userService.Update:{await userService.Update(1, user)}"); 57 | Console.WriteLine($"userService.GetDictionary:{(await userService.GetDictionary())["key"]}"); 58 | await userService.Try(); 59 | await userService.TryThrowException(); 60 | } 61 | catch (RpcRemoteException remoteException) 62 | { 63 | logger.LogError(remoteException.Message); 64 | } 65 | catch 66 | { 67 | } 68 | }).Wait(); 69 | Console.ReadLine(); 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/examples/Echo.Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Echo.Client")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("de8052e6-7cdf-48a0-b06d-5e645a3581aa")] -------------------------------------------------------------------------------- /src/examples/Echo.Client/Properties/PublishProfiles/Default-publish.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding(SupportsShouldProcess=$true)] 2 | param($publishProperties=@{}, $packOutput, $pubProfilePath) 3 | 4 | # to learn more about this file visit https://go.microsoft.com/fwlink/?LinkId=524327 5 | 6 | try{ 7 | if ($publishProperties['ProjectGuid'] -eq $null){ 8 | $publishProperties['ProjectGuid'] = 'de8052e6-7cdf-48a0-b06d-5e645a3581aa' 9 | } 10 | 11 | $publishModulePath = Join-Path (Split-Path $MyInvocation.MyCommand.Path) 'publish-module.psm1' 12 | Import-Module $publishModulePath -DisableNameChecking -Force 13 | 14 | # call Publish-AspNet to perform the publish operation 15 | Publish-AspNet -publishProperties $publishProperties -packOutput $packOutput -pubProfilePath $pubProfilePath 16 | } 17 | catch{ 18 | "An error occurred during publish.`n{0}" -f $_.Exception.Message | Write-Error 19 | } -------------------------------------------------------------------------------- /src/examples/Echo.Common/Echo.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net451;netstandard1.6 5 | Echo.Common 6 | Echo.Common 7 | 1.6.0 8 | $(PackageTargetFallback);dnxcore50 9 | false 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | $(DefineConstants);NET 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/examples/Echo.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Echo.Common")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("c4c4e466-aa51-4514-b0c0-df1d172da6e7")] -------------------------------------------------------------------------------- /src/examples/Echo.Common/UserService.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RabbitTeam/RabbitCloud/8d42a11d1208f55117a411b4248a5abf336161e6/src/examples/Echo.Common/UserService.cs -------------------------------------------------------------------------------- /src/examples/Echo.Server/Echo.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | Echo.Server 6 | Exe 7 | Echo.Server 8 | 1.0.3 9 | $(PackageTargetFallback);dnxcore50 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/examples/Echo.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Address; 6 | using Rabbit.Rpc.Routing; 7 | using Rabbit.Rpc.Runtime.Server; 8 | using System; 9 | using System.Linq; 10 | using System.Net; 11 | using System.Reflection; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using Rabbit.Transport.DotNetty; 15 | 16 | namespace Echo.Server 17 | { 18 | public class Program 19 | { 20 | static Program() 21 | { 22 | //因为没有引用Echo.Common中的任何类型 23 | //所以强制加载Echo.Common程序集以保证Echo.Common在AppDomain中被加载。 24 | Assembly.Load(new AssemblyName("Echo.Common")); 25 | } 26 | 27 | public static void Main(string[] args) 28 | { 29 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 30 | 31 | var serviceCollection = new ServiceCollection(); 32 | 33 | serviceCollection 34 | .AddLogging() 35 | .AddRpcCore() 36 | .AddServiceRuntime() 37 | .UseSharedFileRouteManager("d:\\routes.txt") 38 | .UseDotNettyTransport(); 39 | serviceCollection.AddTransient(); 40 | 41 | var serviceProvider = serviceCollection.BuildServiceProvider(); 42 | 43 | serviceProvider.GetRequiredService() 44 | .AddConsole((c, l) => (int)l >= 3); 45 | 46 | //自动生成服务路由(这边的文件与Echo.Client为强制约束) 47 | { 48 | var serviceEntryManager = serviceProvider.GetRequiredService(); 49 | var addressDescriptors = serviceEntryManager.GetEntries().Select(i => new ServiceRoute 50 | { 51 | Address = new[] 52 | { 53 | new IpAddressModel { Ip = "127.0.0.1", Port = 9981 } 54 | }, 55 | ServiceDescriptor = i.Descriptor 56 | }); 57 | 58 | var serviceRouteManager = serviceProvider.GetRequiredService(); 59 | serviceRouteManager.SetRoutesAsync(addressDescriptors).Wait(); 60 | } 61 | 62 | var serviceHost = serviceProvider.GetRequiredService(); 63 | 64 | Task.Factory.StartNew(async () => 65 | { 66 | //启动主机 67 | await serviceHost.StartAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9981)); 68 | Console.WriteLine($"服务端启动成功,{DateTime.Now}。"); 69 | }); 70 | Console.ReadLine(); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/examples/Echo.Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Echo.Server")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("e5d680f5-d85f-4bf0-b7a9-b3f7d5cecb46")] -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Client/Performances.Net.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net451 5 | win7-x86 6 | Performances.Net.Client 7 | Exe 8 | Performances.Net.Client 9 | false 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Codec.ProtoBuffer; 6 | using Rabbit.Rpc.ProxyGenerator; 7 | using Rabbit.Transport.DotNetty; 8 | using System; 9 | using System.Diagnostics; 10 | using System.Linq; 11 | using System.Threading.Tasks; 12 | 13 | namespace Performances.Net.Client 14 | { 15 | public class Program 16 | { 17 | public static void Main(string[] args) 18 | { 19 | while (true) 20 | { 21 | var serviceCollection = new ServiceCollection(); 22 | 23 | var builder = serviceCollection 24 | .AddLogging() 25 | .AddClient() 26 | .UseSharedFileRouteManager("d:\\routes.txt"); 27 | 28 | IServiceProvider serviceProvider = null; 29 | do 30 | { 31 | Console.WriteLine("请选择测试组合:"); 32 | Console.WriteLine("1.JSON协议+DotNetty传输"); 33 | Console.WriteLine("2.ProtoBuffer协议+DotNetty传输"); 34 | var codec = Console.ReadLine(); 35 | switch (codec) 36 | { 37 | case "1": 38 | builder.UseDotNettyTransport(); 39 | serviceProvider = serviceCollection.BuildServiceProvider(); 40 | break; 41 | 42 | case "2": 43 | builder.UseDotNettyTransport().UseProtoBufferCodec(); 44 | serviceProvider = serviceCollection.BuildServiceProvider(); 45 | break; 46 | 47 | default: 48 | Console.WriteLine("输入错误。"); 49 | continue; 50 | } 51 | } while (serviceProvider == null); 52 | 53 | serviceProvider.GetRequiredService() 54 | .AddConsole((c, l) => (int)l >= 3); 55 | 56 | var serviceProxyGenerater = serviceProvider.GetRequiredService(); 57 | var serviceProxyFactory = serviceProvider.GetRequiredService(); 58 | var services = serviceProxyGenerater.GenerateProxys(new[] { typeof(IUserService) }).ToArray(); 59 | 60 | //创建IUserService的代理。 61 | var userService = serviceProxyFactory.CreateProxy(services.Single(typeof(IUserService).IsAssignableFrom)); 62 | 63 | Task.Run(async () => 64 | { 65 | //预热 66 | await userService.GetUser(1); 67 | 68 | do 69 | { 70 | Console.WriteLine("正在循环 1w次调用 GetUser....."); 71 | //1w次调用 72 | var watch = Stopwatch.StartNew(); 73 | for (var i = 0; i < 10000; i++) 74 | { 75 | await userService.GetUser(1); 76 | } 77 | watch.Stop(); 78 | Console.WriteLine($"1w次调用结束,执行时间:{watch.ElapsedMilliseconds}ms"); 79 | Console.ReadLine(); 80 | } while (true); 81 | }).Wait(); 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Performances.Net.Client")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("9f43167b-c87a-4b94-8a0f-cae853b89619")] -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Server/Performances.Net.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net451 5 | win7-x86 6 | Performances.Net.Server 7 | Exe 8 | Performances.Net.Server 9 | false 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Address; 6 | using Rabbit.Rpc.Codec.ProtoBuffer; 7 | using Rabbit.Rpc.Routing; 8 | using Rabbit.Rpc.Runtime.Server; 9 | using Rabbit.Transport.DotNetty; 10 | using System; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Reflection; 14 | using System.Threading.Tasks; 15 | 16 | namespace Performances.Net.Server 17 | { 18 | public class Program 19 | { 20 | static Program() 21 | { 22 | //因为没有引用Echo.Common中的任何类型 23 | //所以强制加载Echo.Common程序集以保证Echo.Common在AppDomain中被加载。 24 | Assembly.Load(new AssemblyName("Echo.Common")); 25 | } 26 | 27 | public static void Main(string[] args) 28 | { 29 | var serviceCollection = new ServiceCollection(); 30 | 31 | var builder = serviceCollection 32 | .AddLogging() 33 | .AddRpcCore() 34 | .AddServiceRuntime() 35 | .UseSharedFileRouteManager("d:\\routes.txt"); 36 | serviceCollection.AddTransient(); 37 | 38 | IServiceProvider serviceProvider = null; 39 | do 40 | { 41 | Console.WriteLine("请选择测试组合:"); 42 | Console.WriteLine("1.JSON协议+DotNetty传输"); 43 | Console.WriteLine("2.ProtoBuffer协议+DotNetty传输"); 44 | var codec = Console.ReadLine(); 45 | switch (codec) 46 | { 47 | case "1": 48 | builder.UseDotNettyTransport(); 49 | serviceProvider = serviceCollection.BuildServiceProvider(); 50 | break; 51 | 52 | case "2": 53 | builder.UseDotNettyTransport().UseProtoBufferCodec(); 54 | serviceProvider = serviceCollection.BuildServiceProvider(); 55 | break; 56 | 57 | default: 58 | Console.WriteLine("输入错误。"); 59 | continue; 60 | } 61 | } while (serviceProvider == null); 62 | 63 | serviceProvider.GetRequiredService() 64 | .AddConsole((c, l) => (int)l >= 3); 65 | 66 | //自动生成服务路由(这边的文件与Echo.Client为强制约束) 67 | { 68 | var serviceEntryManager = serviceProvider.GetRequiredService(); 69 | var addressDescriptors = serviceEntryManager.GetEntries().Select(i => new ServiceRoute 70 | { 71 | Address = new[] { new IpAddressModel { Ip = "127.0.0.1", Port = 9981 } }, 72 | ServiceDescriptor = i.Descriptor 73 | }); 74 | 75 | var serviceRouteManager = serviceProvider.GetRequiredService(); 76 | serviceRouteManager.SetRoutesAsync(addressDescriptors).Wait(); 77 | } 78 | 79 | var serviceHost = serviceProvider.GetRequiredService(); 80 | 81 | Task.Factory.StartNew(async () => 82 | { 83 | //启动主机 84 | await serviceHost.StartAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9981)); 85 | Console.WriteLine($"服务端启动成功,{DateTime.Now}。"); 86 | }).Wait(); 87 | 88 | Console.WriteLine("按任意键结束本次测试。"); 89 | Console.ReadLine(); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/examples/performances/Performances.Net.Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Performances.Net.Server")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("c5d5ec50-2c75-437e-a019-672442f89362")] -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Client/Performances.NetCoreApp.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | Performances.NetCoreApp.Client 6 | Exe 7 | Performances.NetCoreApp.Client 8 | 1.0.3 9 | $(PackageTargetFallback);dnxcore50 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Codec.ProtoBuffer; 6 | using Rabbit.Rpc.ProxyGenerator; 7 | using Rabbit.Transport.DotNetty; 8 | using System; 9 | using System.Diagnostics; 10 | using System.Linq; 11 | using System.Reflection; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | 15 | namespace Performances.NetCoreApp.Client 16 | { 17 | public class Program 18 | { 19 | public static void Main(string[] args) 20 | { 21 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 22 | 23 | while (true) 24 | { 25 | var serviceCollection = new ServiceCollection(); 26 | 27 | var builder = serviceCollection 28 | .AddLogging() 29 | .AddClient() 30 | .UseSharedFileRouteManager("d:\\routes.txt") 31 | .UseDotNettyTransport(); 32 | 33 | IServiceProvider serviceProvider = null; 34 | while (serviceProvider == null) 35 | { 36 | Console.WriteLine("请输入编解码器协议:"); 37 | Console.WriteLine("1.JSON"); 38 | Console.WriteLine("2.ProtoBuffer"); 39 | var codec = Console.ReadLine(); 40 | switch (codec) 41 | { 42 | case "1": 43 | serviceProvider = serviceCollection.BuildServiceProvider(); 44 | break; 45 | 46 | case "2": 47 | builder.UseProtoBufferCodec(); 48 | serviceProvider = serviceCollection.BuildServiceProvider(); 49 | break; 50 | 51 | default: 52 | Console.WriteLine("输入错误。"); 53 | continue; 54 | } 55 | } 56 | 57 | serviceProvider.GetRequiredService() 58 | .AddConsole((c, l) => (int)l >= 3); 59 | 60 | var serviceProxyGenerater = serviceProvider.GetRequiredService(); 61 | var serviceProxyFactory = serviceProvider.GetRequiredService(); 62 | var services = serviceProxyGenerater.GenerateProxys(new[] { typeof(IUserService) }).ToArray(); 63 | 64 | //创建IUserService的代理。 65 | var userService = serviceProxyFactory.CreateProxy(services.Single(typeof(IUserService).GetTypeInfo().IsAssignableFrom)); 66 | 67 | Task.Run(async () => 68 | { 69 | //预热 70 | await userService.GetUser(1); 71 | 72 | do 73 | { 74 | Console.WriteLine("正在循环 1w次调用 GetUser....."); 75 | //1w次调用 76 | var watch = Stopwatch.StartNew(); 77 | for (var i = 0; i < 10000; i++) 78 | { 79 | await userService.GetUser(1); 80 | } 81 | watch.Stop(); 82 | Console.WriteLine($"1w次调用结束,执行时间:{watch.ElapsedMilliseconds}ms"); 83 | Console.ReadLine(); 84 | } while (true); 85 | }).Wait(); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Performances.NetCoreApp.Client")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("0657fbbf-0e18-4451-ab4e-6dcb6156f2bc")] -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Server/Performances.NetCoreApp.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | Performances.NetCoreApp.Server 6 | Exe 7 | Performances.NetCoreApp.Server 8 | 1.0.3 9 | $(PackageTargetFallback);dnxcore50 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Echo.Common; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Rabbit.Rpc; 5 | using Rabbit.Rpc.Address; 6 | using Rabbit.Rpc.Codec.ProtoBuffer; 7 | using Rabbit.Rpc.Routing; 8 | using Rabbit.Rpc.Runtime.Server; 9 | using Rabbit.Transport.DotNetty; 10 | using System; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Reflection; 14 | using System.Text; 15 | using System.Threading.Tasks; 16 | 17 | namespace Performances.NetCoreApp.Server 18 | { 19 | public class Program 20 | { 21 | static Program() 22 | { 23 | //因为没有引用Echo.Common中的任何类型 24 | //所以强制加载Echo.Common程序集以保证Echo.Common在AppDomain中被加载。 25 | Assembly.Load(new AssemblyName("Echo.Common")); 26 | } 27 | 28 | public static void Main(string[] args) 29 | { 30 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 31 | 32 | var serviceCollection = new ServiceCollection(); 33 | 34 | var builder = serviceCollection 35 | .AddLogging() 36 | .AddRpcCore() 37 | .AddServiceRuntime() 38 | .UseSharedFileRouteManager("d:\\routes.txt") 39 | .UseDotNettyTransport(); 40 | 41 | serviceCollection.AddTransient(); 42 | 43 | IServiceProvider serviceProvider = null; 44 | do 45 | { 46 | Console.WriteLine("请输入编解码器协议:"); 47 | Console.WriteLine("1.JSON"); 48 | Console.WriteLine("2.ProtoBuffer"); 49 | var codec = Console.ReadLine(); 50 | switch (codec) 51 | { 52 | case "1": 53 | serviceProvider = serviceCollection.BuildServiceProvider(); 54 | break; 55 | 56 | case "2": 57 | builder.UseProtoBufferCodec(); 58 | serviceProvider = serviceCollection.BuildServiceProvider(); 59 | break; 60 | 61 | default: 62 | Console.WriteLine("输入错误。"); 63 | continue; 64 | } 65 | } while (serviceProvider == null); 66 | 67 | serviceProvider.GetRequiredService() 68 | .AddConsole((c, l) => (int)l >= 3); 69 | 70 | //自动生成服务路由(这边的文件与Echo.Client为强制约束) 71 | { 72 | var serviceEntryManager = serviceProvider.GetRequiredService(); 73 | var addressDescriptors = serviceEntryManager.GetEntries().Select(i => new ServiceRoute 74 | { 75 | Address = new[] { new IpAddressModel { Ip = "127.0.0.1", Port = 9981 } }, 76 | ServiceDescriptor = i.Descriptor 77 | }); 78 | 79 | var serviceRouteManager = serviceProvider.GetRequiredService(); 80 | serviceRouteManager.SetRoutesAsync(addressDescriptors).Wait(); 81 | } 82 | 83 | var serviceHost = serviceProvider.GetRequiredService(); 84 | 85 | Task.Factory.StartNew(async () => 86 | { 87 | //启动主机 88 | await serviceHost.StartAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9981)); 89 | Console.WriteLine($"服务端启动成功,{DateTime.Now}。"); 90 | }).Wait(); 91 | 92 | Console.WriteLine("按任意键结束本次测试。"); 93 | Console.ReadLine(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/examples/performances/Performances.NetCoreApp.Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Performances.NetCoreApp.Server")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("bf33777d-e3dc-4296-a73d-9716a81b61a4")] -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Messages/ProtoBufferDynamicItem.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | using Rabbit.Rpc.Codec.ProtoBuffer.Utilitys; 3 | using System; 4 | 5 | namespace Rabbit.Rpc.Codec.ProtoBuffer.Messages 6 | { 7 | [ProtoContract] 8 | public class ProtoBufferDynamicItem 9 | { 10 | #region Constructor 11 | 12 | public ProtoBufferDynamicItem() 13 | { 14 | } 15 | 16 | public ProtoBufferDynamicItem(object value) 17 | { 18 | if (value == null) 19 | throw new ArgumentNullException(nameof(value)); 20 | 21 | var valueType = value.GetType(); 22 | var code = Type.GetTypeCode(valueType); 23 | 24 | //如果是简单类型则取短名称,否则取长名称。 25 | if (code != TypeCode.Object) 26 | TypeName = valueType.FullName; 27 | else 28 | TypeName = valueType.AssemblyQualifiedName; 29 | 30 | Content = SerializerUtilitys.Serialize(value); 31 | } 32 | 33 | #endregion Constructor 34 | 35 | #region Property 36 | 37 | [ProtoMember(1)] 38 | public string TypeName { get; set; } 39 | 40 | [ProtoMember(2)] 41 | public byte[] Content { get; set; } 42 | 43 | #endregion Property 44 | 45 | #region Public Method 46 | 47 | public object Get() 48 | { 49 | if (Content == null || TypeName == null) 50 | return null; 51 | 52 | return SerializerUtilitys.Deserialize(Content, Type.GetType(TypeName)); 53 | } 54 | 55 | #endregion Public Method 56 | } 57 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Messages/ProtoBufferRemoteInvokeMessage.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | using Rabbit.Rpc.Messages; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Rabbit.Rpc.Codec.ProtoBuffer.Messages 7 | { 8 | [ProtoContract] 9 | public class ParameterItem 10 | { 11 | #region Constructor 12 | 13 | public ParameterItem(KeyValuePair item) 14 | { 15 | Key = item.Key; 16 | Value = item.Value == null ? null : new ProtoBufferDynamicItem(item.Value); 17 | } 18 | 19 | public ParameterItem() 20 | { 21 | } 22 | 23 | #endregion Constructor 24 | 25 | [ProtoMember(1)] 26 | public string Key { get; set; } 27 | 28 | [ProtoMember(2)] 29 | public ProtoBufferDynamicItem Value { get; set; } 30 | } 31 | 32 | [ProtoContract] 33 | public class ProtoBufferRemoteInvokeMessage 34 | { 35 | public ProtoBufferRemoteInvokeMessage(RemoteInvokeMessage message) 36 | { 37 | ServiceId = message.ServiceId; 38 | Parameters = message.Parameters?.Select(i => new ParameterItem(i)).ToArray(); 39 | } 40 | 41 | public ProtoBufferRemoteInvokeMessage() 42 | { 43 | } 44 | 45 | /// 46 | /// 服务Id。 47 | /// 48 | [ProtoMember(1)] 49 | public string ServiceId { get; set; } 50 | 51 | /// 52 | /// 服务参数。 53 | /// 54 | [ProtoMember(2)] 55 | public ParameterItem[] Parameters { get; set; } 56 | 57 | public RemoteInvokeMessage GetRemoteInvokeMessage() 58 | { 59 | return new RemoteInvokeMessage 60 | { 61 | Parameters = Parameters?.ToDictionary(i => i.Key, i => i.Value?.Get()), 62 | ServiceId = ServiceId 63 | }; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Messages/ProtoBufferRemoteInvokeResultMessage.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | using Rabbit.Rpc.Messages; 3 | 4 | namespace Rabbit.Rpc.Codec.ProtoBuffer.Messages 5 | { 6 | [ProtoContract] 7 | public class ProtoBufferRemoteInvokeResultMessage 8 | { 9 | #region Constructor 10 | 11 | public ProtoBufferRemoteInvokeResultMessage(RemoteInvokeResultMessage message) 12 | { 13 | ExceptionMessage = message.ExceptionMessage; 14 | Result = message.Result == null ? null : new ProtoBufferDynamicItem(message.Result); 15 | } 16 | 17 | public ProtoBufferRemoteInvokeResultMessage() 18 | { 19 | } 20 | 21 | #endregion Constructor 22 | 23 | /// 24 | /// 异常消息。 25 | /// 26 | [ProtoMember(1)] 27 | public string ExceptionMessage { get; set; } 28 | 29 | /// 30 | /// 结果内容。 31 | /// 32 | [ProtoMember(2)] 33 | public ProtoBufferDynamicItem Result { get; set; } 34 | 35 | public RemoteInvokeResultMessage GetRemoteInvokeResultMessage() 36 | { 37 | return new RemoteInvokeResultMessage 38 | { 39 | ExceptionMessage = ExceptionMessage, 40 | Result = Result?.Get() 41 | }; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Messages/ProtoBufferTransportMessage.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | using Rabbit.Rpc.Codec.ProtoBuffer.Utilitys; 3 | using Rabbit.Rpc.Messages; 4 | using System; 5 | 6 | namespace Rabbit.Rpc.Codec.ProtoBuffer.Messages 7 | { 8 | [ProtoContract] 9 | public class ProtoBufferTransportMessage 10 | { 11 | public ProtoBufferTransportMessage(TransportMessage transportMessage) 12 | { 13 | Id = transportMessage.Id; 14 | ContentType = transportMessage.ContentType; 15 | 16 | object contentObject; 17 | if (transportMessage.IsInvokeMessage()) 18 | { 19 | contentObject = new ProtoBufferRemoteInvokeMessage(transportMessage.GetContent()); 20 | } 21 | else if (transportMessage.IsInvokeResultMessage()) 22 | { 23 | contentObject = new ProtoBufferRemoteInvokeResultMessage(transportMessage.GetContent()); 24 | } 25 | else 26 | { 27 | throw new NotSupportedException($"无法支持的消息类型:{ContentType}!"); 28 | } 29 | 30 | Content = SerializerUtilitys.Serialize(contentObject); 31 | } 32 | 33 | public ProtoBufferTransportMessage() 34 | { 35 | } 36 | 37 | /// 38 | /// 消息Id。 39 | /// 40 | [ProtoMember(1)] 41 | public string Id { get; set; } 42 | 43 | /// 44 | /// 消息内容。 45 | /// 46 | [ProtoMember(2)] 47 | public byte[] Content { get; set; } 48 | 49 | /// 50 | /// 内容类型。 51 | /// 52 | [ProtoMember(3)] 53 | public string ContentType { get; set; } 54 | 55 | /// 56 | /// 是否调用消息。 57 | /// 58 | /// 如果是则返回true,否则返回false。 59 | public bool IsInvokeMessage() 60 | { 61 | return ContentType == typeof(RemoteInvokeMessage).FullName; 62 | } 63 | 64 | /// 65 | /// 是否是调用结果消息。 66 | /// 67 | /// 如果是则返回true,否则返回false。 68 | public bool IsInvokeResultMessage() 69 | { 70 | return ContentType == typeof(RemoteInvokeResultMessage).FullName; 71 | } 72 | 73 | public TransportMessage GetTransportMessage() 74 | { 75 | var message = new TransportMessage 76 | { 77 | ContentType = ContentType, 78 | Id = Id, 79 | Content = null 80 | }; 81 | 82 | object contentObject; 83 | if (IsInvokeMessage()) 84 | { 85 | contentObject = 86 | SerializerUtilitys.Deserialize(Content).GetRemoteInvokeMessage(); 87 | } 88 | else if (IsInvokeResultMessage()) 89 | { 90 | contentObject = 91 | SerializerUtilitys.Deserialize(Content) 92 | .GetRemoteInvokeResultMessage(); 93 | } 94 | else 95 | { 96 | throw new NotSupportedException($"无法支持的消息类型:{ContentType}!"); 97 | } 98 | 99 | message.Content = contentObject; 100 | 101 | return message; 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc.Codec.ProtoBuffer")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("1467cdfa-20e4-4510-9d6b-fd2425add51b")] -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/ProtoBufferTransportMessageCodecFactory.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Transport.Codec; 2 | 3 | namespace Rabbit.Rpc.Codec.ProtoBuffer 4 | { 5 | public class ProtoBufferTransportMessageCodecFactory : ITransportMessageCodecFactory 6 | { 7 | #region Field 8 | 9 | private readonly ITransportMessageEncoder _transportMessageEncoder = new ProtoBufferTransportMessageEncoder(); 10 | private readonly ITransportMessageDecoder _transportMessageDecoder = new ProtoBufferTransportMessageDecoder(); 11 | 12 | #endregion Field 13 | 14 | #region Implementation of ITransportMessageCodecFactory 15 | 16 | /// 17 | /// 获取编码器。 18 | /// 19 | /// 编码器实例。 20 | public ITransportMessageEncoder GetEncoder() 21 | { 22 | return _transportMessageEncoder; 23 | } 24 | 25 | /// 26 | /// 获取解码器。 27 | /// 28 | /// 解码器实例。 29 | public ITransportMessageDecoder GetDecoder() 30 | { 31 | return _transportMessageDecoder; 32 | } 33 | 34 | #endregion Implementation of ITransportMessageCodecFactory 35 | } 36 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/ProtoBufferTransportMessageDecoder.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Codec.ProtoBuffer.Messages; 2 | using Rabbit.Rpc.Codec.ProtoBuffer.Utilitys; 3 | using Rabbit.Rpc.Messages; 4 | using Rabbit.Rpc.Transport.Codec; 5 | 6 | namespace Rabbit.Rpc.Codec.ProtoBuffer 7 | { 8 | public class ProtoBufferTransportMessageDecoder : ITransportMessageDecoder 9 | { 10 | #region Implementation of ITransportMessageDecoder 11 | 12 | public TransportMessage Decode(byte[] data) 13 | { 14 | var message = SerializerUtilitys.Deserialize(data); 15 | 16 | return message.GetTransportMessage(); 17 | } 18 | 19 | #endregion Implementation of ITransportMessageDecoder 20 | } 21 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/ProtoBufferTransportMessageEncoder.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Codec.ProtoBuffer.Messages; 2 | using Rabbit.Rpc.Codec.ProtoBuffer.Utilitys; 3 | using Rabbit.Rpc.Messages; 4 | using Rabbit.Rpc.Transport.Codec; 5 | 6 | namespace Rabbit.Rpc.Codec.ProtoBuffer 7 | { 8 | public class ProtoBufferTransportMessageEncoder : ITransportMessageEncoder 9 | { 10 | #region Implementation of ITransportMessageEncoder 11 | 12 | public byte[] Encode(TransportMessage message) 13 | { 14 | var transportMessage = new ProtoBufferTransportMessage(message) 15 | { 16 | Id = message.Id, 17 | ContentType = message.ContentType 18 | }; 19 | 20 | return SerializerUtilitys.Serialize(transportMessage); 21 | } 22 | 23 | #endregion Implementation of ITransportMessageEncoder 24 | } 25 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Rabbit.Rpc.Codec.ProtoBuffer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 基于ProtoBuffer的Rpc消息编解码器扩展。 5 | © RabbitHub. All rights reserved. 6 | 1.0.0-alpha1 7 | majian 8 | net451;netstandard1.6 9 | Rabbit.Rpc.Codec.ProtoBuffer 10 | Rabbit.Rpc.Codec.ProtoBuffer 11 | RabbitHub;RPC 12 | http://www.rabbithub.com/icon.png 13 | https://github.com/RabbitTeam/Rpc 14 | https://github.com/RabbitTeam/Rpc/blob/master/LICENSE 15 | 1.6.0 16 | $(PackageTargetFallback);dnxcore50 17 | false 18 | false 19 | false 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $(DefineConstants);NET 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Rabbit.Rpc.Codec.ProtoBuffer.csproj.migration_in_place_backup: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {99A64337-0C1B-4B8A-8BB5-367AB6DA8A75} 8 | Library 9 | Properties 10 | Rabbit.Rpc.Codec.ProtoBuffer 11 | Rabbit.Rpc.Codec.ProtoBuffer 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | ..\..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.0\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll 37 | True 38 | 39 | 40 | ..\..\..\packages\protobuf-net.2.1.0-alpha-1\lib\net45\protobuf-net.dll 41 | True 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {cef91c5e-7986-4c78-afe5-656917448300} 62 | Rabbit.Rpc 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/RpcServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Rabbit.Rpc.Codec.ProtoBuffer 2 | { 3 | public static class RpcServiceCollectionExtensions 4 | { 5 | /// 6 | /// 使用ProtoBuffer编解码器。 7 | /// 8 | /// Rpc服务构建者。 9 | /// Rpc服务构建者。 10 | public static IRpcBuilder UseProtoBufferCodec(this IRpcBuilder builder) 11 | { 12 | return builder.UseCodec(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/extensions/codecs/Rabbit.Rpc.Codec.ProtoBuffer/Utilitys/SerializerUtilitys.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | using System; 3 | using System.IO; 4 | 5 | namespace Rabbit.Rpc.Codec.ProtoBuffer.Utilitys 6 | { 7 | public static class SerializerUtilitys 8 | { 9 | public static byte[] Serialize(object instance) 10 | { 11 | using (var stream = new MemoryStream()) 12 | { 13 | #if NET 14 | Serializer.NonGeneric.Serialize(stream, instance); 15 | #else 16 | Serializer.Serialize(stream,instance); 17 | #endif 18 | return stream.ToArray(); 19 | } 20 | } 21 | 22 | public static object Deserialize(byte[] data, Type type) 23 | { 24 | if (data == null) 25 | return null; 26 | using (var stream = new MemoryStream(data)) 27 | { 28 | #if NET 29 | return Serializer.NonGeneric.Deserialize(type, stream); 30 | #else 31 | return Serializer.Deserialize(type, stream); 32 | #endif 33 | } 34 | } 35 | 36 | public static T Deserialize(byte[] data) 37 | { 38 | if (data == null) 39 | return default(T); 40 | using (var stream = new MemoryStream(data)) 41 | { 42 | return Serializer.Deserialize(stream); 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/extensions/coordinates/Rabbit.Rpc.Coordinate.Zookeeper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc.Coordinate.Zookeeper")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("a7126f11-f0c3-4ae0-a62d-8bd9e1f3399f")] -------------------------------------------------------------------------------- /src/extensions/coordinates/Rabbit.Rpc.Coordinate.Zookeeper/Rabbit.Rpc.Coordinate.Zookeeper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 基于ZooKeeper的Rpc服务协调扩展。 5 | © RabbitHub. All rights reserved. 6 | 1.0.0-alpha1 7 | majian 8 | net45;net451;netstandard1.6 9 | Rabbit.Rpc.Coordinate.Zookeeper 10 | Rabbit.Rpc.Coordinate.Zookeeper 11 | RabbitHub;RPC 12 | http://www.rabbithub.com/icon.png 13 | https://github.com/RabbitTeam/Rpc 14 | https://github.com/RabbitTeam/Rpc/blob/master/LICENSE 15 | 1.6.0 16 | $(PackageTargetFallback);dnxcore50 17 | false 18 | false 19 | false 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | $(DefineConstants);NET 42 | 43 | 44 | 45 | $(DefineConstants);NET 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/extensions/coordinates/Rabbit.Rpc.Coordinate.Zookeeper/RpcServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | using Rabbit.Rpc.Routing; 4 | using Rabbit.Rpc.Serialization; 5 | 6 | namespace Rabbit.Rpc.Coordinate.Zookeeper 7 | { 8 | public static class RpcServiceCollectionExtensions 9 | { 10 | /// 11 | /// 设置共享文件路由管理者。 12 | /// 13 | /// Rpc服务构建者。 14 | /// ZooKeeper设置信息。 15 | /// Rpc服务构建者。 16 | public static IRpcBuilder UseZooKeeperRouteManager(this IRpcBuilder builder, ZooKeeperServiceRouteManager.ZookeeperConfigInfo configInfo) 17 | { 18 | return builder.UseRouteManager(provider => 19 | new ZooKeeperServiceRouteManager( 20 | configInfo, 21 | provider.GetRequiredService>(), 22 | provider.GetRequiredService>(), 23 | provider.GetRequiredService(), 24 | provider.GetRequiredService>())); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/Adaper/TransportMessageChannelHandlerAdapter.cs: -------------------------------------------------------------------------------- 1 | using DotNetty.Buffers; 2 | using DotNetty.Transport.Channels; 3 | using Rabbit.Rpc.Transport.Codec; 4 | 5 | namespace Rabbit.Transport.DotNetty.Adaper 6 | { 7 | internal class TransportMessageChannelHandlerAdapter : ChannelHandlerAdapter 8 | { 9 | private readonly ITransportMessageDecoder _transportMessageDecoder; 10 | 11 | public TransportMessageChannelHandlerAdapter(ITransportMessageDecoder transportMessageDecoder) 12 | { 13 | _transportMessageDecoder = transportMessageDecoder; 14 | } 15 | 16 | #region Overrides of ChannelHandlerAdapter 17 | 18 | public override void ChannelRead(IChannelHandlerContext context, object message) 19 | { 20 | var buffer = (IByteBuffer)message; 21 | var data = buffer.ToArray(); 22 | var transportMessage = _transportMessageDecoder.Decode(data); 23 | context.FireChannelRead(transportMessage); 24 | } 25 | 26 | #endregion Overrides of ChannelHandlerAdapter 27 | } 28 | } -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/DotNettyMessageSender.cs: -------------------------------------------------------------------------------- 1 | using DotNetty.Buffers; 2 | using DotNetty.Transport.Channels; 3 | using Rabbit.Rpc.Messages; 4 | using Rabbit.Rpc.Transport; 5 | using Rabbit.Rpc.Transport.Codec; 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | namespace Rabbit.Transport.DotNetty 10 | { 11 | /// 12 | /// 基于DotNetty的消息发送者基类。 13 | /// 14 | public abstract class DotNettyMessageSender 15 | { 16 | private readonly ITransportMessageEncoder _transportMessageEncoder; 17 | 18 | protected DotNettyMessageSender(ITransportMessageEncoder transportMessageEncoder) 19 | { 20 | _transportMessageEncoder = transportMessageEncoder; 21 | } 22 | 23 | protected IByteBuffer GetByteBuffer(TransportMessage message) 24 | { 25 | var data = _transportMessageEncoder.Encode(message); 26 | 27 | var buffer = Unpooled.Buffer(data.Length, data.Length); 28 | return buffer.WriteBytes(data); 29 | } 30 | } 31 | 32 | /// 33 | /// 基于DotNetty客户端的消息发送者。 34 | /// 35 | public class DotNettyMessageClientSender : DotNettyMessageSender, IMessageSender, IDisposable 36 | { 37 | private readonly IChannel _channel; 38 | 39 | public DotNettyMessageClientSender(ITransportMessageEncoder transportMessageEncoder, IChannel channel) : base(transportMessageEncoder) 40 | { 41 | _channel = channel; 42 | } 43 | 44 | #region Implementation of IDisposable 45 | 46 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 47 | public void Dispose() 48 | { 49 | Task.Run(async () => 50 | { 51 | await _channel.DisconnectAsync(); 52 | }).Wait(); 53 | } 54 | 55 | #endregion Implementation of IDisposable 56 | 57 | #region Implementation of IMessageSender 58 | 59 | /// 60 | /// 发送消息。 61 | /// 62 | /// 消息内容。 63 | /// 一个任务。 64 | public async Task SendAsync(TransportMessage message) 65 | { 66 | var buffer = GetByteBuffer(message); 67 | await _channel.WriteAsync(buffer); 68 | } 69 | 70 | /// 71 | /// 发送消息并清空缓冲区。 72 | /// 73 | /// 消息内容。 74 | /// 一个任务。 75 | public async Task SendAndFlushAsync(TransportMessage message) 76 | { 77 | var buffer = GetByteBuffer(message); 78 | await _channel.WriteAndFlushAsync(buffer); 79 | } 80 | 81 | #endregion Implementation of IMessageSender 82 | } 83 | 84 | /// 85 | /// 基于DotNetty服务端的消息发送者。 86 | /// 87 | public class DotNettyServerMessageSender : DotNettyMessageSender, IMessageSender 88 | { 89 | private readonly IChannelHandlerContext _context; 90 | 91 | public DotNettyServerMessageSender(ITransportMessageEncoder transportMessageEncoder, IChannelHandlerContext context) : base(transportMessageEncoder) 92 | { 93 | _context = context; 94 | } 95 | 96 | #region Implementation of IMessageSender 97 | 98 | /// 99 | /// 发送消息。 100 | /// 101 | /// 消息内容。 102 | /// 一个任务。 103 | public Task SendAsync(TransportMessage message) 104 | { 105 | var buffer = GetByteBuffer(message); 106 | return _context.WriteAsync(buffer); 107 | } 108 | 109 | /// 110 | /// 发送消息并清空缓冲区。 111 | /// 112 | /// 消息内容。 113 | /// 一个任务。 114 | public Task SendAndFlushAsync(TransportMessage message) 115 | { 116 | var buffer = GetByteBuffer(message); 117 | return _context.WriteAndFlushAsync(buffer); 118 | } 119 | 120 | #endregion Implementation of IMessageSender 121 | } 122 | } -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/DotNettyServerMessageListener.cs: -------------------------------------------------------------------------------- 1 | using DotNetty.Codecs; 2 | using DotNetty.Transport.Bootstrapping; 3 | using DotNetty.Transport.Channels; 4 | using DotNetty.Transport.Channels.Sockets; 5 | using Microsoft.Extensions.Logging; 6 | using Rabbit.Rpc.Messages; 7 | using Rabbit.Rpc.Transport; 8 | using Rabbit.Rpc.Transport.Codec; 9 | using Rabbit.Transport.DotNetty.Adaper; 10 | using System; 11 | using System.Net; 12 | using System.Threading.Tasks; 13 | 14 | namespace Rabbit.Transport.DotNetty 15 | { 16 | public class DotNettyServerMessageListener : IMessageListener, IDisposable 17 | { 18 | #region Field 19 | 20 | private readonly ILogger _logger; 21 | private readonly ITransportMessageDecoder _transportMessageDecoder; 22 | private readonly ITransportMessageEncoder _transportMessageEncoder; 23 | private IChannel _channel; 24 | 25 | #endregion Field 26 | 27 | #region Constructor 28 | 29 | public DotNettyServerMessageListener(ILogger logger, ITransportMessageCodecFactory codecFactory) 30 | { 31 | _logger = logger; 32 | _transportMessageEncoder = codecFactory.GetEncoder(); 33 | _transportMessageDecoder = codecFactory.GetDecoder(); 34 | } 35 | 36 | #endregion Constructor 37 | 38 | #region Implementation of IMessageListener 39 | 40 | public event ReceivedDelegate Received; 41 | 42 | /// 43 | /// 触发接收到消息事件。 44 | /// 45 | /// 消息发送者。 46 | /// 接收到的消息。 47 | /// 一个任务。 48 | public async Task OnReceived(IMessageSender sender, TransportMessage message) 49 | { 50 | if (Received == null) 51 | return; 52 | await Received(sender, message); 53 | } 54 | 55 | #endregion Implementation of IMessageListener 56 | 57 | public async Task StartAsync(EndPoint endPoint) 58 | { 59 | if (_logger.IsEnabled(LogLevel.Debug)) 60 | _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); 61 | 62 | var bossGroup = new MultithreadEventLoopGroup(1); 63 | var workerGroup = new MultithreadEventLoopGroup(); 64 | var bootstrap = new ServerBootstrap(); 65 | bootstrap 66 | .Group(bossGroup, workerGroup) 67 | .Channel() 68 | .Option(ChannelOption.SoBacklog, 100) 69 | .ChildHandler(new ActionChannelInitializer(channel => 70 | { 71 | var pipeline = channel.Pipeline; 72 | pipeline.AddLast(new LengthFieldPrepender(4)); 73 | pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4)); 74 | pipeline.AddLast(new TransportMessageChannelHandlerAdapter(_transportMessageDecoder)); 75 | pipeline.AddLast(new ServerHandler(async (contenxt, message) => 76 | { 77 | var sender = new DotNettyServerMessageSender(_transportMessageEncoder, contenxt); 78 | await OnReceived(sender, message); 79 | }, _logger)); 80 | })); 81 | _channel = await bootstrap.BindAsync(endPoint); 82 | 83 | if (_logger.IsEnabled(LogLevel.Debug)) 84 | _logger.LogDebug($"服务主机启动成功,监听地址:{endPoint}。"); 85 | } 86 | 87 | #region Implementation of IDisposable 88 | 89 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 90 | public void Dispose() 91 | { 92 | Task.Run(async () => 93 | { 94 | await _channel.DisconnectAsync(); 95 | }).Wait(); 96 | } 97 | 98 | #endregion Implementation of IDisposable 99 | 100 | #region Help Class 101 | 102 | private class ServerHandler : ChannelHandlerAdapter 103 | { 104 | private readonly Action _readAction; 105 | private readonly ILogger _logger; 106 | 107 | public ServerHandler(Action readAction, ILogger logger) 108 | { 109 | _readAction = readAction; 110 | _logger = logger; 111 | } 112 | 113 | #region Overrides of ChannelHandlerAdapter 114 | 115 | public override void ChannelRead(IChannelHandlerContext context, object message) 116 | { 117 | Task.Run(() => 118 | { 119 | var transportMessage = (TransportMessage)message; 120 | 121 | _readAction(context, transportMessage); 122 | }); 123 | } 124 | 125 | public override void ChannelReadComplete(IChannelHandlerContext context) 126 | { 127 | context.Flush(); 128 | } 129 | 130 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) 131 | { 132 | if (_logger.IsEnabled(LogLevel.Error)) 133 | _logger.LogError($"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。", exception); 134 | } 135 | 136 | #endregion Overrides of ChannelHandlerAdapter 137 | } 138 | 139 | #endregion Help Class 140 | } 141 | } -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Transport.DotNetty")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("d906803f-f09d-436e-9a95-37db9aac1f13")] -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/Rabbit.Transport.DotNetty.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 基于DotNetty的Rpc通信扩展。 5 | © RabbitHub. All rights reserved. 6 | 1.0.0-alpha1 7 | majian 8 | net451;netstandard1.6 9 | Rabbit.Transport.DotNetty 10 | Rabbit.Transport.DotNetty 11 | RabbitHub;RPC 12 | http://www.rabbithub.com/icon.png 13 | https://github.com/RabbitTeam/Rpc 14 | https://github.com/RabbitTeam/Rpc/blob/master/LICENSE 15 | 1.6.0 16 | $(PackageTargetFallback);dnxcore50 17 | false 18 | false 19 | false 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/extensions/transports/Rabbit.Transport.DotNetty/RpcServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Rabbit.Rpc; 3 | using Rabbit.Rpc.Runtime.Server; 4 | using Rabbit.Rpc.Runtime.Server.Implementation; 5 | using Rabbit.Rpc.Transport; 6 | 7 | namespace Rabbit.Transport.DotNetty 8 | { 9 | public static class RpcServiceCollectionExtensions 10 | { 11 | /// 12 | /// 使用DotNetty进行传输。 13 | /// 14 | /// Rpc服务构建者。 15 | /// Rpc服务构建者。 16 | public static IRpcBuilder UseDotNettyTransport(this IRpcBuilder builder) 17 | { 18 | var services = builder.Services; 19 | 20 | services.AddSingleton(); 21 | 22 | services.AddSingleton(); 23 | 24 | services.AddSingleton(provider => new DefaultServiceHost(async endPoint => 25 | { 26 | var messageListener = provider.GetRequiredService(); 27 | await messageListener.StartAsync(endPoint); 28 | return messageListener; 29 | }, provider.GetRequiredService())); 30 | 31 | return builder; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/tests/Rabbit.Rpc.Tests/AddressSelectors/RandomAddressSelectorTests.cs: -------------------------------------------------------------------------------- 1 | using Rabbit.Rpc.Address; 2 | using Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors; 3 | using Rabbit.Rpc.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Xunit; 7 | 8 | namespace Rabbit.Rpc.Tests.AddressSelectors 9 | { 10 | public class RandomAddressSelectorTests 11 | { 12 | [Fact] 13 | public async void RandomAddressTest() 14 | { 15 | IAddressSelector selector = new RandomAddressSelector(); 16 | 17 | var context = GetSelectContext(); 18 | 19 | var list = new List(); 20 | for (var i = 0; i < 100; i++) 21 | list.Add(await selector.SelectAsync(context)); 22 | 23 | Assert.True(list.Distinct().Count() > 1); 24 | 25 | selector = new RandomAddressSelector((min, max) => 0); 26 | 27 | for (var i = 0; i < 100; i++) 28 | Assert.Equal(context.Address.First(), await selector.SelectAsync(context)); 29 | } 30 | 31 | private static AddressSelectContext GetSelectContext() 32 | { 33 | return new AddressSelectContext 34 | { 35 | Address = Enumerable.Range(1, 100).Select(i => new IpAddressModel("127.0.0.1", i)), 36 | Descriptor = new ServiceDescriptor 37 | { 38 | Id = "service1" 39 | } 40 | }; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/tests/Rabbit.Rpc.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc.Tests")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("0ad2a7dc-819d-4f74-bb61-3a973f5e4e01")] -------------------------------------------------------------------------------- /src/tests/Rabbit.Rpc.Tests/Rabbit.Rpc.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.0 5 | Rabbit.Rpc.Tests 6 | Rabbit.Rpc.Tests 7 | true 8 | 1.6.0 9 | $(PackageTargetFallback);dnxcore50 10 | 1.0.3 11 | false 12 | false 13 | false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/tests/Rabbit.Rpc.Tests/ServiceRouteManagers/SharedFileServiceRouteManagerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Rabbit.Rpc.Routing; 3 | using Rabbit.Rpc.Routing.Implementation; 4 | using System; 5 | using System.IO; 6 | 7 | namespace Rabbit.Rpc.Tests.ServiceRouteManagers 8 | { 9 | public class SharedFileServiceRouteManagerTests : ServiceRouteManagerTests 10 | { 11 | public SharedFileServiceRouteManagerTests() 12 | { 13 | var routeFile = Path.Combine(AppContext.BaseDirectory, "routes.txt"); 14 | var services = new ServiceCollection(); 15 | services 16 | .AddLogging() 17 | .AddRpcCore() 18 | .UseSharedFileRouteManager(routeFile); 19 | var provider = services.BuildServiceProvider(); 20 | 21 | ServiceRouteManager = (SharedFileServiceRouteManager)provider.GetRequiredService(); 22 | } 23 | 24 | #region Overrides of ServiceRouteManagerTests 25 | 26 | protected override IServiceRouteManager ServiceRouteManager { get; } 27 | 28 | #endregion Overrides of ServiceRouteManagerTests 29 | } 30 | } -------------------------------------------------------------------------------- /src/tests/Rabbit.Rpc.Tests/ServiceRouteManagers/ZooKeeperServiceRouteManagerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Rabbit.Rpc.Coordinate.Zookeeper; 3 | using Rabbit.Rpc.Routing; 4 | 5 | namespace Rabbit.Rpc.Tests.ServiceRouteManagers 6 | { 7 | public class ZooKeeperServiceRouteManagerTests : ServiceRouteManagerTests 8 | { 9 | public ZooKeeperServiceRouteManagerTests() 10 | { 11 | var services = new ServiceCollection(); 12 | services 13 | .AddLogging() 14 | .AddRpcCore() 15 | .UseZooKeeperRouteManager(new ZooKeeperServiceRouteManager.ZookeeperConfigInfo("172.18.20.132:2181", 16 | "/dotnet/unitTest/serviceRoutes")); 17 | var provider = services.BuildServiceProvider(); 18 | 19 | ServiceRouteManager = (ZooKeeperServiceRouteManager)provider.GetRequiredService(); 20 | } 21 | 22 | #region Overrides of ServiceRouteManagerTests 23 | 24 | protected override IServiceRouteManager ServiceRouteManager { get; } 25 | 26 | #endregion Overrides of ServiceRouteManagerTests 27 | } 28 | } -------------------------------------------------------------------------------- /src/tools/Rabbit.Rpc.ClientGenerator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Rabbit.Rpc.ClientGenerator")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("dd3e4f3a-dcd2-480c-b9f0-954ae53a37ea")] -------------------------------------------------------------------------------- /src/tools/Rabbit.Rpc.ClientGenerator/Rabbit.Rpc.ClientGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | Rabbit.Rpc.ClientGenerator 6 | Exe 7 | Rabbit.Rpc.ClientGenerator 8 | 1.0.3 9 | $(PackageTargetFallback);dnxcore50 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------