瀏覽代碼

升级SDK部分Nuget包,添加Grpc套件,以及CodeFirst,GRPC服务注册发现Consul等

CrazyIter 5 年之前
父節點
當前提交
f8a56e8846
共有 89 個文件被更改,包括 4826 次插入61 次删除
  1. 27 0
      TEAMModelOS.GRPC/Program.cs
  2. 12 0
      TEAMModelOS.GRPC/Properties/launchSettings.json
  3. 26 0
      TEAMModelOS.GRPC/Services/GreeterService.cs
  4. 43 0
      TEAMModelOS.GRPC/Startup.cs
  5. 14 0
      TEAMModelOS.GRPC/TEAMModelOS.GRPC.csproj
  6. 10 0
      TEAMModelOS.GRPC/appsettings.Development.json
  7. 15 0
      TEAMModelOS.GRPC/appsettings.json
  8. 26 39
      TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3Repository.cs
  9. 19 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Discovery/IServiceDiscovery.cs
  10. 21 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Discovery/IServiceRegister.cs
  11. 19 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/IGrpcService.cs
  12. 18 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/ILoadBalancer.cs
  13. 55 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/InternalException.cs
  14. 67 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/LoggerAccessor.cs
  15. 18 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/Consts.cs
  16. 29 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/ErrorModel.cs
  17. 23 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/GrpcErrorCode.cs
  18. 21 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/LogType.cs
  19. 88 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/MonitorModel.cs
  20. 42 0
      TEAMModelOS.SDK/Module/Grpc/Abstract/Model/ServiceRegisterModel.cs
  21. 170 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/IApplicationBuilderExtensions.cs
  22. 40 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/JaegerTracingInterceptor.cs
  23. 116 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/MonitorInterceptor.cs
  24. 59 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/ThrottleInterceptor.cs
  25. 75 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/ServerInterceptor.cs
  26. 95 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/BindMethodFinder.cs
  27. 38 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/BinderServiceMethodProvider.cs
  28. 175 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/GrpcMethodHelper.cs
  29. 189 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/ProviderServiceBinder.cs
  30. 78 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/RegisterServiceHosted.cs
  31. 63 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/Options/GrpcServerOptions.cs
  32. 105 0
      TEAMModelOS.SDK/Module/Grpc/AspNetCore/ServiceCollectionExtensions.cs
  33. 97 0
      TEAMModelOS.SDK/Module/Grpc/Client/GrpcClientApp.cs
  34. 51 0
      TEAMModelOS.SDK/Module/Grpc/Client/GrpcClientManager.cs
  35. 66 0
      TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/CientCallTimeout.cs
  36. 79 0
      TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/ClientJaegerTracingInterceptor.cs
  37. 107 0
      TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/ClientMonitorInterceptor.cs
  38. 83 0
      TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/ClientInterceptor.cs
  39. 47 0
      TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/InterceptorCallInvoker.cs
  40. 82 0
      TEAMModelOS.SDK/Module/Grpc/Client/Internal/AutoChannelCallInvoker.cs
  41. 170 0
      TEAMModelOS.SDK/Module/Grpc/Client/Internal/ChannelPool.cs
  42. 26 0
      TEAMModelOS.SDK/Module/Grpc/Client/LoadBalancer/RandomLoadBalancer.cs
  43. 33 0
      TEAMModelOS.SDK/Module/Grpc/Client/LoadBalancer/RoundLoadBalancer.cs
  44. 46 0
      TEAMModelOS.SDK/Module/Grpc/Client/Model/ChannelConfig.cs
  45. 13 0
      TEAMModelOS.SDK/Module/Grpc/Client/Model/ChannelInfo.cs
  46. 43 0
      TEAMModelOS.SDK/Module/Grpc/Client/Options/GrpcClientOptions.cs
  47. 53 0
      TEAMModelOS.SDK/Module/Grpc/Client/Options/JaegerOptions.cs
  48. 187 0
      TEAMModelOS.SDK/Module/Grpc/Client/ServiceCollectionExtensions.cs
  49. 50 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/CmdService.cs
  50. 15 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/IGrpcBaseService.cs
  51. 83 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MetaService.cs
  52. 91 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MetaServiceAspnetCore.cs
  53. 14 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/AddDelSaveResponseEnableRQ.cs
  54. 14 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/AddDelThrottleRQ.cs
  55. 24 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/CmdRS.cs
  56. 12 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/InfoRQ.cs
  57. 28 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/InfoRS.cs
  58. 30 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MetaModel.cs
  59. 11 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInfoRQ.cs
  60. 14 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInfoRS.cs
  61. 23 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInvokeRQ.cs
  62. 10 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInvokeRS.cs
  63. 38 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/ProtoInfo.cs
  64. 13 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/ServerConsts.cs
  65. 24 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/XmlCommentInfo.cs
  66. 44 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MonitorManager.cs
  67. 42 0
      TEAMModelOS.SDK/Module/Grpc/Common/BaseService/ThrottleManager.cs
  68. 52 0
      TEAMModelOS.SDK/Module/Grpc/Common/CommonError.cs
  69. 34 0
      TEAMModelOS.SDK/Module/Grpc/Common/DateTimeExtensions.cs
  70. 31 0
      TEAMModelOS.SDK/Module/Grpc/Common/ExceptionExtensions.cs
  71. 31 0
      TEAMModelOS.SDK/Module/Grpc/Common/HostBuilderExtensions.cs
  72. 179 0
      TEAMModelOS.SDK/Module/Grpc/Common/Internal/ProtoCommentGenerator.cs
  73. 231 0
      TEAMModelOS.SDK/Module/Grpc/Common/Internal/ProtoGenerator.cs
  74. 18 0
      TEAMModelOS.SDK/Module/Grpc/Common/Internal/ServerCallContextAccessor.cs
  75. 30 0
      TEAMModelOS.SDK/Module/Grpc/Common/Internal/ServiceProviderAccessor.cs
  76. 126 0
      TEAMModelOS.SDK/Module/Grpc/Common/JsonSerialization.cs
  77. 104 0
      TEAMModelOS.SDK/Module/Grpc/Common/NetHelper.cs
  78. 43 0
      TEAMModelOS.SDK/Module/Grpc/Common/ObjectExtensions.cs
  79. 43 0
      TEAMModelOS.SDK/Module/Grpc/Common/Options/GrpcExtensionsOptions.cs
  80. 41 0
      TEAMModelOS.SDK/Module/Grpc/Common/ProtobufExtensions.cs
  81. 82 0
      TEAMModelOS.SDK/Module/Grpc/Common/ReflectorExtensions.cs
  82. 32 0
      TEAMModelOS.SDK/Module/Grpc/Discovery/Consul/ConsulServiceDiscovery.cs
  83. 129 0
      TEAMModelOS.SDK/Module/Grpc/Discovery/Consul/ConsulServiceRegister.cs
  84. 25 0
      TEAMModelOS.SDK/Module/Grpc/Discovery/ServiceCollectionExtensions.cs
  85. 23 14
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  86. 2 2
      TEAMModelOS.Service/Services/PowerPoint/Implement/HtexService.cs
  87. 1 1
      TEAMModelOS.Service/TEAMModelOS.Service.csproj
  88. 6 0
      TEAMModelOS.sln
  89. 4 5
      TEAMModelOS/TEAMModelOS.csproj

+ 27 - 0
TEAMModelOS.GRPC/Program.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
+namespace TEAMModelOS.GRPC
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        // Additional configuration is required to successfully run gRPC on macOS.
+        // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                });
+    }
+}

+ 12 - 0
TEAMModelOS.GRPC/Properties/launchSettings.json

@@ -0,0 +1,12 @@
+{
+  "profiles": {
+    "TEAMModelOS.GRPC": {
+      "commandName": "Project",
+      "launchBrowser": false,
+      "applicationUrl": "https://localhost:5001",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 26 - 0
TEAMModelOS.GRPC/Services/GreeterService.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Microsoft.Extensions.Logging;
+
+namespace TEAMModelOS.GRPC
+{
+    public class GreeterService : Greeter.GreeterBase
+    {
+        private readonly ILogger<GreeterService> _logger;
+        public GreeterService(ILogger<GreeterService> logger)
+        {
+            _logger = logger;
+        }
+
+        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
+        {
+            return Task.FromResult(new HelloReply
+            {
+                Message = "Hello " + request.Name
+            });
+        }
+    }
+}

+ 43 - 0
TEAMModelOS.GRPC/Startup.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace TEAMModelOS.GRPC
+{
+    public class Startup
+    {
+        // This method gets called by the runtime. Use this method to add services to the container.
+        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddGrpc();
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+        {
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+
+            app.UseRouting();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapGrpcService<GreeterService>();
+
+                endpoints.MapGet("/", async context =>
+                {
+                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+                });
+            });
+        }
+    }
+}

+ 14 - 0
TEAMModelOS.GRPC/TEAMModelOS.GRPC.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Protos\" />
+  </ItemGroup>
+</Project>

+ 10 - 0
TEAMModelOS.GRPC/appsettings.Development.json

@@ -0,0 +1,10 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Debug",
+      "System": "Information",
+      "Grpc": "Information",
+      "Microsoft": "Information"
+    }
+  }
+}

+ 15 - 0
TEAMModelOS.GRPC/appsettings.json

@@ -0,0 +1,15 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*",
+  "Kestrel": {
+    "EndpointDefaults": {
+      "Protocols": "Http2"
+    }
+  }
+}

+ 26 - 39
TEAMModelOS.SDK/Module/AzureCosmosDBV3/AzureCosmosDBV3Repository.cs

@@ -285,13 +285,13 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                         }
                         }
                         ));
                         ));
                 });
                 });
-                await Task.WhenAll(tasks);
-                lists.ForEach(async x => {
-                    if (container.cache && RedisHelper.Instance != null)
-                    {
+                await Task.WhenAll(tasks); 
+                if (container.cache && RedisHelper.Instance != null)
+                {
+                    lists.ForEach(async x => {
                         await RedisHelper.HDelAsync(CacheCosmosPrefix + container.container.Id,x.Value );
                         await RedisHelper.HDelAsync(CacheCosmosPrefix + container.container.Id,x.Value );
-                    }
-                });
+                    });
+                }
             }
             }
             stopwatch.Stop();
             stopwatch.Stop();
             return idPks;
             return idPks;
@@ -336,13 +336,12 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                         }
                         }
                     ));
                     ));
                 });
                 });
-                await Task.WhenAll(tasks);
-                lists.ForEach(async x => {
-                    if (container.cache && RedisHelper.Instance != null)
-                    {
+                await Task.WhenAll(tasks); if (container.cache && RedisHelper.Instance != null)
+                {
+                    lists.ForEach(async x => {
                         await RedisHelper.HDelAsync(CacheCosmosPrefix + container.container.Id, x.id);
                         await RedisHelper.HDelAsync(CacheCosmosPrefix + container.container.Id, x.id);
-                    }
-                });
+                    });
+                }
             }
             }
             stopwatch.Stop();
             stopwatch.Stop();
             return idPks;
             return idPks;
@@ -460,18 +459,10 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
         {
         {
             if (DocumentCollectionDict.TryGetValue(CollectionName, out CosmosModelInfo container))
             if (DocumentCollectionDict.TryGetValue(CollectionName, out CosmosModelInfo container))
             {
             {
-                //StringBuilder sql = new StringBuilder("select  value count(c)  from c");
-                //SQLHelper.GetSQL(dict, ref sql);
-                //CosmosDbQuery cosmosDbQuery = new CosmosDbQuery
-                //{
-                //    QueryText = sql.ToString()
-
-                //};
                 dict.Remove("@CURRPAGE");
                 dict.Remove("@CURRPAGE");
                 dict.Remove("@PAGESIZE");
                 dict.Remove("@PAGESIZE");
                 dict.Remove("@ASC");
                 dict.Remove("@ASC");
                 dict.Remove("@DESC");
                 dict.Remove("@DESC");
-
                 StringBuilder sql = new StringBuilder("select  value count(c)  from c");
                 StringBuilder sql = new StringBuilder("select  value count(c)  from c");
                 CosmosDbQuery cosmosDbQuery = SQLHelperParametric.GetSQL(dict, sql);
                 CosmosDbQuery cosmosDbQuery = SQLHelperParametric.GetSQL(dict, sql);
                 QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
                 QueryRequestOptions queryRequestOptions = GetDefaultQueryRequestOptions(itemsPerPage: GetEffectivePageSize(itemsPerPage, maxItemCount));
@@ -658,8 +649,6 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
 
 
         public async Task<List<T>> SaveAll<T>(List<T> enyites) where T : ID
         public async Task<List<T>> SaveAll<T>(List<T> enyites) where T : ID
         {
         {
-
-
             int pages = (int)Math.Ceiling((double)enyites.Count / pageSize);
             int pages = (int)Math.Ceiling((double)enyites.Count / pageSize);
             CosmosModelInfo container = await InitializeCollection<T>();
             CosmosModelInfo container = await InitializeCollection<T>();
             bool flag = false;
             bool flag = false;
@@ -682,7 +671,6 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                     KeyValuePair<PartitionKey, Stream> keyValue = new KeyValuePair<PartitionKey, Stream>(new PartitionKey(o.ToString()), stream);
                     KeyValuePair<PartitionKey, Stream> keyValue = new KeyValuePair<PartitionKey, Stream>(new PartitionKey(o.ToString()), stream);
                     itemsToInsert.Add(keyValue);
                     itemsToInsert.Add(keyValue);
                 });
                 });
-
                 List<Task> tasks = new List<Task>(lists.Count);
                 List<Task> tasks = new List<Task>(lists.Count);
                 itemsToInsert.ForEach(item =>
                 itemsToInsert.ForEach(item =>
                 {
                 {
@@ -697,15 +685,14 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                             }
                             }
                         }
                         }
                         ));
                         ));
-
                 });
                 });
                 await Task.WhenAll(tasks);
                 await Task.WhenAll(tasks);
-                lists.ForEach(async x => {
-                    if (container.cache && RedisHelper.Instance != null)
-                    {
+                if (container.cache && RedisHelper.Instance != null)
+                {
+                    lists.ForEach(async x => {
                         await RedisHelper.HSetAsync(CacheCosmosPrefix+container.container.Id, x.id, x);
                         await RedisHelper.HSetAsync(CacheCosmosPrefix+container.container.Id, x.id, x);
-                    }
-                });
+                    });
+                }
             }
             }
             if (container.cache && RedisHelper.Instance != null&&!flag) {
             if (container.cache && RedisHelper.Instance != null&&!flag) {
                 await RedisHelper.ExpireAsync(CacheCosmosPrefix + container.container.Id, timeoutSeconds);
                 await RedisHelper.ExpireAsync(CacheCosmosPrefix + container.container.Id, timeoutSeconds);
@@ -776,12 +763,12 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                         ));
                         ));
                 });
                 });
                 await Task.WhenAll(tasks);
                 await Task.WhenAll(tasks);
-                lists.ForEach(async x => {
-                    if (container.cache && RedisHelper.Instance != null)
-                    {
+                if (container.cache && RedisHelper.Instance != null)
+                {
+                    lists.ForEach(async x => {
                         await RedisHelper.HSetAsync(CacheCosmosPrefix + container.container.Id, x.id, x);
                         await RedisHelper.HSetAsync(CacheCosmosPrefix + container.container.Id, x.id, x);
-                    }
-                });
+                    });
+                }
             }
             }
             if (container.cache && RedisHelper.Instance != null&&!flag)
             if (container.cache && RedisHelper.Instance != null&&!flag)
             {
             {
@@ -865,12 +852,12 @@ namespace TEAMModelOS.SDK.Module.AzureCosmosDBV3
                         ));
                         ));
                 });
                 });
                 await Task.WhenAll(tasks);
                 await Task.WhenAll(tasks);
-                lists.ForEach(async x => {
-                    if (container.cache && RedisHelper.Instance != null)
-                    {
+                if (container.cache && RedisHelper.Instance != null)
+                {
+                    lists.ForEach(async x => {
                         await RedisHelper.HSetAsync(CacheCosmosPrefix + container.container.Id, x.id, x);
                         await RedisHelper.HSetAsync(CacheCosmosPrefix + container.container.Id, x.id, x);
-                    }
-                });
+                    });
+                }
             }
             }
             if (container.cache && RedisHelper.Instance != null&&!flag)
             if (container.cache && RedisHelper.Instance != null&&!flag)
             {
             {

+ 19 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Discovery/IServiceDiscovery.cs

@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace Grpc.Extension.Abstract.Discovery
+{
+    /// <summary>
+    /// 服务发现
+    /// </summary>
+    public interface IServiceDiscovery
+    {
+        /// <summary>
+        /// 获取服务地址列表
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <param name="discoveryUrl"></param>
+        /// <param name="serviceTag"></param>
+        /// <returns></returns>
+        List<string> GetEndpoints(string serviceName, string discoveryUrl, string serviceTag);
+    }
+}

+ 21 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Discovery/IServiceRegister.cs

@@ -0,0 +1,21 @@
+using Grpc.Extension.Abstract.Model;
+
+namespace Grpc.Extension.Abstract.Discovery
+{
+    /// <summary>
+    /// 服务注册
+    /// </summary>
+    public interface IServiceRegister
+    {
+        /// <summary>
+        /// 服务注册
+        /// </summary>
+        /// <param name="model"></param>
+        void RegisterService(ServiceRegisterModel model);
+
+        /// <summary>
+        /// 服务反注册
+        /// </summary>
+        void DeregisterService();
+    }
+}

+ 19 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/IGrpcService.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Abstract
+{
+    /// <summary>
+    /// GrpcService(CodeFirst)
+    /// </summary>
+    public interface IGrpcService
+    {
+
+    }
+
+    /// <summary>
+    /// 非Grpc方法
+    /// </summary>
+    public sealed class NotGrpcMethodAttribute : Attribute { }
+}

+ 18 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/ILoadBalancer.cs

@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace Grpc.Extension.Abstract
+{
+    /// <summary>
+    /// 负载均衡
+    /// </summary>
+    public interface ILoadBalancer
+    {
+        /// <summary>
+        /// 选择Endpoint
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <param name="endpoints"></param>
+        /// <returns></returns>
+        string SelectEndpoint(string serviceName, List<string> endpoints);
+    }
+}

+ 55 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/InternalException.cs

@@ -0,0 +1,55 @@
+using Grpc.Extension.Abstract.Model;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Abstract
+{
+    /// <summary>
+    /// Grpc.Extension内部异常
+    /// </summary>
+    public class InternalException : Exception
+    {
+        private int Code { get; set; }
+
+        /// <summary>
+        /// InternalException
+        /// </summary>
+        /// <param name="code"></param>
+        public InternalException(int code)
+        {
+            this.SetCode(code);
+        }
+
+        /// <summary>
+        /// InternalException
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="message"></param>
+        public InternalException(int code, string message) : base(message)
+        {
+            this.SetCode(code);
+        }
+
+        /// <summary>
+        /// InternalException
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="message"></param>
+        /// <param name="innerException"></param>
+        public InternalException(int code, string message, Exception innerException) : base(message, innerException)
+        {
+            this.SetCode(code);
+        }
+
+        /// <summary>
+        /// SetCode
+        /// </summary>
+        /// <param name="code"></param>
+        public void SetCode(int code)
+        {
+            this.Code = GrpcErrorCode.DefaultErrorCode + code;
+            this.Data.Add("ErrorCode", this.Code);
+        }
+    }
+}

+ 67 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/LoggerAccessor.cs

@@ -0,0 +1,67 @@
+using Grpc.Extension.Abstract.Model;
+using System;
+
+namespace Grpc.Extension.Abstract
+{
+    /// <summary>
+    /// 日志访问
+    /// </summary>
+    public class LoggerAccessor
+    {
+        /// <summary>
+        /// LoggerError
+        /// </summary>
+        /// <param name="ex"></param>
+        /// <param name="logType"></param>
+        public delegate void LoggerErrorAction(Exception ex, LogType logType = LogType.ServerLog);
+        /// <summary>
+        /// LoggerMonitor
+        /// </summary>
+        /// <param name="msg"></param>
+        /// <param name="logType"></param>
+        public delegate void LoggerMonitorAction(string msg, LogType logType = LogType.ServerLog);
+
+        private static Lazy<LoggerAccessor> instance = new Lazy<LoggerAccessor>(() => new LoggerAccessor(), true);
+
+        /// <summary>
+        /// Instance
+        /// </summary>
+        public static LoggerAccessor Instance
+        {
+            get { return instance.Value; }
+        }
+        private LoggerAccessor()
+        {
+        }
+
+        /// <summary>
+        /// 写异常日志
+        /// </summary>
+        public event LoggerErrorAction LoggerError;
+
+        /// <summary>
+        /// 触发写异常日志
+        /// </summary>
+        /// <param name="ex"></param>
+        /// <param name="logType"></param>
+        public void OnLoggerError(Exception ex, LogType logType = LogType.ServerLog)
+        {
+            LoggerError?.Invoke(ex, logType);
+        }
+
+        /// <summary>
+        /// 写监控日志
+        /// </summary>
+        public event LoggerMonitorAction LoggerMonitor;
+
+        /// <summary>
+        /// 触发写监控日志
+        /// </summary>
+        /// <param name="msg"></param>
+        /// <param name="logType"></param>
+        public void OnLoggerMonitor(string msg, LogType logType = LogType.ServerLog)
+        {
+            LoggerMonitor?.Invoke(msg, logType);
+        }
+    }
+}

+ 18 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/Consts.cs

@@ -0,0 +1,18 @@
+namespace Grpc.Extension.Abstract
+{
+    /// <summary>
+    /// Consts
+    /// </summary>
+    public class Consts
+    {
+        /// <summary>
+        /// TraceId
+        /// </summary>
+        public const string TraceId = "traceid";
+
+        /// <summary>
+        /// OpenTraceId
+        /// </summary>
+        public const string OpenTraceId = "jaeger";
+    }
+}

+ 29 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/ErrorModel.cs

@@ -0,0 +1,29 @@
+namespace Grpc.Extension.Abstract.Model
+{
+    /// <summary>
+    /// 统一错误模型
+    /// </summary>
+    public class ErrorModel
+    {
+        /// <summary>
+        /// 错误码
+        /// </summary>
+        public int Code { get; set; }
+        /// <summary>
+        /// 状态
+        /// </summary>
+        public int Status { get; set; }
+        /// <summary>
+        /// Exception.Message
+        /// </summary>
+        public string Detail { get; set; }
+        /// <summary>
+        /// FlatException
+        /// </summary>
+        public string Internal { get; set; }
+        /// <summary>
+        /// 备用
+        /// </summary>
+        public string Content { get; set; }
+    }
+}

+ 23 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/GrpcErrorCode.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Abstract.Model
+{
+    /// <summary>
+    /// GrpcErrorCode
+    /// </summary>
+    public class GrpcErrorCode
+    {
+        /// <summary>
+        /// 默认错误码
+        /// </summary>
+        public static int DefaultErrorCode = 1;
+
+        /// <summary>
+        /// 内部异常
+        /// </summary>
+        public const int Internal = 0;
+
+    }
+}

+ 21 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/LogType.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Abstract.Model
+{
+    /// <summary>
+    /// 日志类型
+    /// </summary>
+    public enum LogType
+    {
+        /// <summary>
+        /// 服务端日志
+        /// </summary>
+        ServerLog = 0,
+        /// <summary>
+        /// 客户端日志
+        /// </summary>
+        ClientLog = 1,
+    }
+}

+ 88 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/MonitorModel.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+
+
+namespace Grpc.Extension.Abstract.Model
+{
+    /// <summary>
+    /// 日志监控实体
+    /// </summary>
+    [Serializable]
+    public class MonitorModel
+    {
+        /// <summary>
+        /// MonitorModel
+        /// </summary>
+        public MonitorModel()
+        {
+            RequestId = Guid.NewGuid().ToString();
+            RequestTime = DateTime.Now;
+        }
+
+        /// <summary>
+        /// 请求Id
+        /// </summary>
+        public string RequestId { get; set; }
+
+        /// <summary>
+        /// 客户端Ip
+        /// </summary>
+        public string ClientIp { get; set; }
+        
+        /// <summary>
+        /// 请求时间
+        /// </summary>
+        public DateTime RequestTime { get; set; }
+
+        /// <summary>
+        /// 请求Url
+        /// </summary>
+        public string RequestUrl { get; set; }
+
+        /// <summary>
+        /// 请求参数
+        /// </summary>
+        public string RequestData { get; set; }
+
+        /// <summary>
+        /// 请求头
+        /// </summary>
+        public Dictionary<string, string> RequestHeaders { get; set; }
+        /// <summary>
+        /// 多层调用的追踪id
+        /// </summary>
+        public string TraceId { get; set; }
+
+
+        /// <summary>
+        /// ok | error
+        /// </summary>
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 响应时间
+        /// </summary>
+        public DateTime ResponseTime { get; set; }
+
+        /// <summary>
+        /// 响应数据
+        /// </summary>
+        public string ResponseData { get; set; }
+
+        /// <summary>
+        /// 异常信息
+        /// </summary>
+        public string Exception { get; set; }
+
+        /// <summary>
+        /// 总耗时
+        /// </summary>
+        public double TotalElapsed => (ResponseTime - RequestTime).TotalMilliseconds;
+
+        /// <summary>
+        /// 访问上下信息的预留属性
+        /// </summary>
+        public ConcurrentDictionary<string, object> Items { get; set; } = new ConcurrentDictionary<string, object>();
+    }
+}

+ 42 - 0
TEAMModelOS.SDK/Module/Grpc/Abstract/Model/ServiceRegisterModel.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Abstract.Model
+{
+    /// <summary>
+    /// 服务注册模型
+    /// </summary>
+    public class ServiceRegisterModel
+    {
+        /// <summary>
+        /// Grpc服务Ip
+        /// </summary>
+        public string ServiceIp { get; set; }
+
+        /// <summary>
+        /// Grpc服务Port
+        /// </summary>
+        public int ServicePort { get; set; }
+
+        /// <summary>
+        /// 服务注册地址(http://192.168.8.6:8500)
+        /// </summary>
+        public string DiscoveryUrl { get; set; }
+
+        /// <summary>
+        /// 服务注册名
+        /// </summary>
+        public string DiscoveryServiceName { get; set; }
+
+        /// <summary>
+        /// 服务注册Tags
+        /// </summary>
+        public string DiscoveryServiceTags { get; set; }
+
+        /// <summary>
+        /// 服务TTL(秒)
+        /// </summary>
+        public int DiscoveryTTLInterval { get; set; } = 10;
+    }
+}

+ 170 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/IApplicationBuilderExtensions.cs

@@ -0,0 +1,170 @@
+using Grpc.Extension;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.BaseService;
+using Grpc.Extension.Client;
+using Grpc.Extension.Common.Internal;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.DependencyInjection;
+using OpenTracing;
+using OpenTracing.Util;
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace Grpc.Extension.AspNetCore
+{
+    public static class IApplicationBuilderExtensions
+    {
+        /// <summary>
+        /// 使用Grpc扩展
+        /// </summary>
+        /// <typeparam name="TStartup">实现IGrpcService的类所在程序集下的任意类</typeparam>
+        /// <param name="builder"></param>
+        /// <param name="configureOptions"></param>
+        /// <returns></returns>
+        public static IApplicationBuilder UseGrpcExtensions<TStartup>(this IApplicationBuilder builder, Action<GrpcExtensionsOptions> configureOptions = null)
+        {
+            ServiceProviderAccessor.SetServiceProvider(builder.ApplicationServices);
+            //注入基本配制
+            configureOptions?.Invoke(GrpcExtensionsOptions.Instance);
+            //使用基础服务
+            builder.UseEndpoints(endpoints => {
+                endpoints.MapIGrpcServices<TStartup>();
+                //使用基础服务
+                endpoints.MapGrpcService<CmdService>();
+                endpoints.MapGrpcService<MetaServiceAspnetCore>();
+            });
+            //默认使用
+            builder.InitGrpcOptions()//初始化配制
+                .UseLoggerFactory()//使用LoggerFactory
+                .UseJaeger();//使用Jaeger
+
+            return builder;
+        }
+
+        /// <summary>
+        /// MapGrpcService(TStartup程序集下所有的IGrpcService)
+        /// </summary>
+        /// <typeparam name="TStartup">实现IGrpcService的类所在程序集下的任意类</typeparam>
+        /// <param name="endpoints"></param>
+        public static void MapIGrpcServices<TStartup>(this IEndpointRouteBuilder endpoints)
+        {
+            //获取所有IGrpcService并调用MapGrpcService方法
+            var grpcServices = typeof(TStartup).Assembly.GetTypes().Where(p => typeof(IGrpcService).IsAssignableFrom(p) && p.IsClass);
+            var method = typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService");
+            foreach (var service in grpcServices)
+            {
+                var mapGrpcService = method.MakeGenericMethod(service);
+                mapGrpcService.Invoke(null, new object[] { endpoints });
+            }
+        }
+
+        /// <summary>
+        /// 初始化配制
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <returns></returns>
+        private static IApplicationBuilder InitGrpcOptions(this IApplicationBuilder builder)
+        {
+            var provider = builder.ApplicationServices;
+            var serverOptions = provider.GetService<IOptions<GrpcServerOptions>>().Value;
+
+            //Jaeger配置
+            if (serverOptions.Jaeger != null && string.IsNullOrWhiteSpace(serverOptions.Jaeger.ServiceName))
+                serverOptions.Jaeger.ServiceName = serverOptions.DiscoveryServiceName;
+
+            #region 默认的客户端配制
+
+            var clientOptions = provider.GetService<IOptions<GrpcClientOptions>>().Value;
+            clientOptions.DiscoveryUrl = serverOptions.DiscoveryUrl;
+            clientOptions.DefaultErrorCode = serverOptions.DefaultErrorCode;
+            clientOptions.Jaeger = serverOptions.Jaeger;
+            clientOptions.GrpcCallTimeOut = serverOptions.GrpcCallTimeOut;
+
+            #endregion
+
+            return builder;
+        }
+
+        /// <summary>
+        /// 注入Grpc,Discovery配制
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <param name="configureOptions"></param>
+        /// <returns></returns>
+        public static IApplicationBuilder UseGrpcOptions(this IApplicationBuilder builder, Action<GrpcServerOptions> configureOptions)
+        {
+            var options = ServiceProviderAccessor.GetService<IOptions<GrpcServerOptions>>().Value;
+            configureOptions(options);
+
+            return builder;
+        }
+
+        /// <summary>
+        /// 有Jaeger配制就使用Jaeger
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <returns></returns>
+        private static IApplicationBuilder UseJaeger(this IApplicationBuilder builder)
+        {
+            var serverOptions = ServiceProviderAccessor.GetService<IOptions<GrpcServerOptions>>().Value;
+            if (serverOptions.Jaeger != null && string.IsNullOrWhiteSpace(serverOptions.Jaeger.ServiceName))
+                serverOptions.Jaeger.ServiceName = serverOptions.DiscoveryServiceName;
+
+            if (serverOptions.Jaeger?.CheckConfig() == true)
+            {
+                var tracer = ServiceProviderAccessor.GetService<ITracer>();
+                if (tracer != null) GlobalTracer.Register(tracer);
+            }
+            return builder;
+        }
+
+        /// <summary>
+        /// 使用LoggerFactory
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <returns></returns>
+        private static IApplicationBuilder UseLoggerFactory(this IApplicationBuilder builder)
+        {
+            var loggerFactory = ServiceProviderAccessor.GetService<ILoggerFactory>();
+            var logger = loggerFactory.CreateLogger<IApplicationBuilder>();
+            var loggerAccess = loggerFactory.CreateLogger("grpc.access");
+
+            LoggerAccessor.Instance.LoggerError += (ex, type) => logger.LogError(ex.ToString());
+            LoggerAccessor.Instance.LoggerMonitor += (msg, type) => loggerAccess.LogInformation(msg);
+
+            return builder;
+        }
+
+        /// <summary>
+        /// 配制日志(默认使用LoggerFactory)
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <param name="configureLogger"></param>
+        /// <returns></returns>
+        public static IApplicationBuilder UseLogger(this IApplicationBuilder builder, Action<LoggerAccessor> configureLogger)
+        {
+            configureLogger(LoggerAccessor.Instance);
+
+            return builder;
+        }
+
+        /// <summary>
+        /// CodeFirst生成proto文件
+        /// </summary>
+        /// <param name="builder"></param>
+        /// <param name="dir">生成目录</param>
+        /// <param name="spiltProto">是否拆分service和message协议</param>
+        /// <returns></returns>
+        public static IApplicationBuilder UseProtoGenerate(this IApplicationBuilder builder, string dir, bool spiltProto = true)
+        {
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+                ProtoGenerator.Gen(dir, spiltProto);
+
+            return builder;
+        }
+    }
+}

+ 40 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/JaegerTracingInterceptor.cs

@@ -0,0 +1,40 @@
+using Grpc.Core;
+using OpenTracing.Util;
+using System;
+using System.Threading.Tasks;
+using System.Linq;
+using Jaeger;
+using Grpc.Extension.Common;
+using Grpc.Extension.Abstract;
+
+namespace Grpc.Extension.Interceptors
+{
+    /// <summary>
+    /// JaegerTracingMiddleware
+    /// </summary>
+    internal class JaegerTracingInterceptor : ServerInterceptor
+    {
+        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+        {
+            var header = context.RequestHeaders.Where(p => p.Key == Consts.OpenTraceId).FirstOrDefault();
+            var spanBuilder = GlobalTracer.Instance.BuildSpan(context.Method).WithTag("Request", request?.ToJson() ?? "");
+            if(header != null)
+            {
+                var spanContext = SpanContext.ContextFromString(header.Value);
+                spanBuilder = spanBuilder.AsChildOf(spanContext);
+            }
+            using (var scope = spanBuilder.StartActive(true))
+            {
+                try
+                {
+                    return await continuation(request, context);
+                }
+                catch (Exception ex)
+                {
+                    scope.Span.SetTag("Error", ex.ToString());
+                    throw;
+                }
+            }
+        }
+    }
+}

+ 116 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/MonitorInterceptor.cs

@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using Grpc.Core;
+using System.Linq;
+using System.Threading.Tasks;
+using Grpc.Extension.Common;
+using Grpc.Extension.BaseService;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Abstract.Model;
+using Grpc.Extension.Common.Internal;
+using Grpc.Extension.BaseService.Model;
+
+namespace Grpc.Extension.Interceptors
+{
+    /// <summary>
+    /// 性能监控,记录日志
+    /// </summary>
+    internal class MonitorInterceptor : ServerInterceptor
+    {
+        private async Task<TResponse> Monitor<TRequest, TResponse>(object request, 
+            ServerCallContext context, Delegate continuation, object response = null)
+        {
+            ServerCallContextAccessor.Current = context;
+            var trace = context.RequestHeaders.FirstOrDefault(q => q.Key == Consts.TraceId);
+            if (trace == null)
+            {
+                trace = new Metadata.Entry(Consts.TraceId, Guid.NewGuid().ToString());
+                context.RequestHeaders.Add(trace);
+            }
+            var model = new MonitorModel
+            {
+                ClientIp = context.Peer,
+                RequestUrl = context.Method,
+                //RequestData = request?.ToJson(),
+                RequestHeaders = context.RequestHeaders.ToDictionary(p => p.Key, p => p.Value),
+                TraceId = trace.Value
+            };
+            if (request is TRequest)
+            {
+                model.RequestData = request?.ToJson();
+            }
+            else if(request is IAsyncStreamReader<TRequest>)
+            {
+                var requests = new List<TRequest>();
+                //await requestStream.ForEachAsync(req=> {
+                //    requests.Add(req);
+                //    return Task.CompletedTask;
+                //});
+                model.RequestData = requests?.ToJson();
+            }
+            try
+            {
+                if (response == null)
+                {
+                    var result = await (continuation.DynamicInvoke(request, context) as Task<TResponse>);
+                    model.Status = "ok";
+
+                    model.ResponseData = MonitorManager.Instance.SaveResponseMethodEnable(context.Method) ? result?.ToJson() : ServerConsts.NotResponseMsg;
+
+                    return result;
+                }
+                else
+                {
+                    await (continuation.DynamicInvoke(request, response, context) as Task);
+                    return default(TResponse);
+                }
+            }
+            catch (Exception ex)
+            {
+                var rpcEx = CommonError.BuildRpcException(ex);
+                var dataRequest = rpcEx.Data["Request"];
+                if (dataRequest != null)
+                {
+                    model.Items.TryAdd("ClientRequest", dataRequest);
+                    rpcEx.Data["Request"] = model;
+                }
+                else
+                {
+                    rpcEx.Data.Add("Request", model);
+                }
+                model.Exception = rpcEx.ToString();
+                model.Status = "error";
+                LoggerAccessor.Instance.OnLoggerError(rpcEx);
+                throw rpcEx;
+            }
+            finally
+            {
+                ServerCallContextAccessor.Current = null;
+                model.ResponseTime = DateTime.Now;
+                LoggerAccessor.Instance.OnLoggerMonitor(model.ToJson());
+            }
+        }
+
+        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request,
+            ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+        {
+            return await Monitor<TRequest, TResponse>(request, context, continuation);
+        }
+
+        public override async Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream,
+            ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            return await Monitor<TRequest, TResponse>(requestStream, context, continuation);
+        }
+
+        public override async Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            await Monitor<TRequest, TResponse>(request, context, continuation,responseStream);
+        }
+
+        public override async Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            await Monitor<TRequest, TResponse>(requestStream, context, continuation, responseStream);
+        }
+    }
+}

+ 59 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/Server/ThrottleInterceptor.cs

@@ -0,0 +1,59 @@
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Extension.BaseService;
+using Grpc.Extension.BaseService.Model;
+
+namespace Grpc.Extension.Interceptors
+{
+    /// <summary>
+    /// 手动熔断处理
+    /// </summary>
+    internal class ThrottleInterceptor : ServerInterceptor
+    {
+        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request,
+            ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+        {
+            if (ThrottleManager.Instance.IsThrottled(context.Method))
+            {
+                throw new RpcException(new Status(
+                    StatusCode.Cancelled,
+                    Newtonsoft.Json.JsonConvert.SerializeObject(new { Code = 503, Detail = ServerConsts.ThrottledMsg })));
+            }
+            return await continuation(request, context);
+        }
+
+        public override async Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream,
+            ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            if (ThrottleManager.Instance.IsThrottled(context.Method))
+            {
+                throw new RpcException(new Status(
+                    StatusCode.Cancelled,
+                    Newtonsoft.Json.JsonConvert.SerializeObject(new { Code = 503, Detail = ServerConsts.ThrottledMsg })));
+            }
+            return await continuation(requestStream, context);
+        }
+
+        public override async Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            if (ThrottleManager.Instance.IsThrottled(context.Method))
+            {
+                throw new RpcException(new Status(
+                    StatusCode.Cancelled,
+                    Newtonsoft.Json.JsonConvert.SerializeObject(new { Code = 503, Detail = ServerConsts.ThrottledMsg })));
+            }
+            await continuation(request, responseStream, context);
+        }
+
+        public override async Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            if (ThrottleManager.Instance.IsThrottled(context.Method))
+            {
+                throw new RpcException(new Status(
+                    StatusCode.Cancelled,
+                    Newtonsoft.Json.JsonConvert.SerializeObject(new { Code = 503, Detail = ServerConsts.ThrottledMsg })));
+            }
+            await continuation(requestStream, responseStream, context);
+        }
+    }
+}

+ 75 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Interceptors/ServerInterceptor.cs

@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+
+namespace Grpc.Extension.Interceptors
+{
+    /// <summary>
+    /// 服务端拦截器
+    /// </summary>
+    public abstract class ServerInterceptor : Interceptor
+    {
+        /// <summary>
+        /// 单请求
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request,
+            ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// 客户端流请求
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="requestStream"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, 
+            ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            return continuation(requestStream, context);
+        }
+
+        /// <summary>
+        /// 服务端流返回
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="responseStream"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            return continuation(request, responseStream, context);
+        }
+
+        /// <summary>
+        /// 双向流
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="requestStream"></param>
+        /// <param name="responseStream"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
+        {
+            return continuation(requestStream, responseStream, context);
+        }
+    }
+}

+ 95 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/BindMethodFinder.cs

@@ -0,0 +1,95 @@
+using Grpc.Core;
+using Grpc.Extension.Abstract;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Grpc.Extension.AspNetCore.Internal
+{
+    internal static class BindMethodFinder
+    {
+        private const BindingFlags BindMethodBindingFlags = BindingFlags.Public | BindingFlags.Static;
+
+        internal static MethodInfo? GetBindMethod(Type serviceType)
+        {
+            if (typeof(IGrpcService).IsAssignableFrom(serviceType))
+            {
+                return typeof(GrpcMethodHelper).GetMethod("BindService");
+            }
+            else
+            {
+                // Prefer finding the bind method using attribute on the generated service
+                var bindMethodInfo = GetBindMethodUsingAttribute(serviceType);
+
+                if (bindMethodInfo == null)
+                {
+                    // Fallback to searching for bind method using known type hierarchy that Grpc.Tools generates
+                    bindMethodInfo = GetBindMethodFallback(serviceType);
+                }
+                return bindMethodInfo;
+            }
+        }
+
+        internal static MethodInfo? GetBindMethodUsingAttribute(Type serviceType)
+        {
+            Type? currentServiceType = serviceType;
+            BindServiceMethodAttribute? bindServiceMethod;
+            do
+            {
+                // Search through base types for bind service attribute
+                // We need to know the base service type because it is used with GetMethod below
+                bindServiceMethod = currentServiceType.GetCustomAttribute<BindServiceMethodAttribute>();
+                if (bindServiceMethod != null)
+                {
+                    // Bind method will be public and static
+                    // Two parameters: ServiceBinderBase and the service type
+                    return bindServiceMethod.BindType.GetMethod(
+                        bindServiceMethod.BindMethodName,
+                        BindMethodBindingFlags,
+                        binder: null,
+                        new[] { typeof(ServiceBinderBase), currentServiceType },
+                        Array.Empty<ParameterModifier>());
+                }
+            } while ((currentServiceType = currentServiceType.BaseType) != null);
+
+            return null;
+        }
+
+        internal static MethodInfo? GetBindMethodFallback(Type serviceType)
+        {
+            // Search for the generated service base class
+            var baseType = GetServiceBaseType(serviceType);
+            if (baseType == null)
+            {
+                return null;
+            }
+
+            // We need to call Foo.BindService from the declaring type.
+            var declaringType = baseType.DeclaringType;
+
+            // The method we want to call is public static void BindService(ServiceBinderBase, BaseType)
+            return declaringType?.GetMethod(
+                "BindService",
+                BindMethodBindingFlags,
+                binder: null,
+                new[] { typeof(ServiceBinderBase), baseType },
+                Array.Empty<ParameterModifier>());
+        }
+
+        private static Type? GetServiceBaseType(Type serviceImplementation)
+        {
+            // TService is an implementation of the gRPC service. It ultimately derives from Foo.TServiceBase base class.
+            // We need to access the static BindService method on Foo which implicitly derives from Object.
+            var baseType = serviceImplementation.BaseType;
+
+            // Handle services that have multiple levels of inheritence
+            while (baseType?.BaseType?.BaseType != null)
+            {
+                baseType = baseType.BaseType;
+            }
+
+            return baseType;
+        }
+    }
+}

+ 38 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/BinderServiceMethodProvider.cs

@@ -0,0 +1,38 @@
+using Grpc.AspNetCore.Server.Model;
+using Grpc.Extension.Abstract;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace Grpc.Extension.AspNetCore.Internal
+{
+    internal class BinderServiceMethodProvider<TService> : IServiceMethodProvider<TService> where TService : class
+    {
+        public void OnServiceMethodDiscovery(ServiceMethodProviderContext<TService> context)
+        {
+            var bindMethodInfo = BindMethodFinder.GetBindMethod(typeof(TService));
+
+            // Invoke BindService(ServiceBinderBase, BaseType)
+            if (bindMethodInfo != null)
+            {
+                // The second parameter is always the service base type
+                var serviceParameter = bindMethodInfo.GetParameters()[1];
+
+                var binder = new ProviderServiceBinder<TService>(context, serviceParameter.ParameterType);
+
+                try
+                {
+                    if (typeof(IGrpcService).IsAssignableFrom(typeof(TService)))
+                        bindMethodInfo.Invoke(null, new object?[] { binder, typeof(TService) });
+                    else
+                    {
+                        bindMethodInfo.Invoke(null, new object?[] { binder, null });
+                    }
+                }
+                catch (Exception ex)
+                {
+                    throw new InvalidOperationException($"Error binding gRPC service '{typeof(TService).Name}'.", ex);
+                }
+            }
+        }
+    }
+}

+ 175 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/GrpcMethodHelper.cs

@@ -0,0 +1,175 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.BaseService;
+using Grpc.Extension.BaseService.Model;
+using Grpc.Extension.Common;
+using Grpc.Extension.Common.Internal;
+
+namespace Grpc.Extension.AspNetCore.Internal
+{
+    // ReSharper disable once IdentifierTypo
+    internal static class GrpcMethodHelper
+    {
+        // ReSharper disable once InconsistentNaming
+        private static readonly MethodInfo buildMethod;
+        // ReSharper disable once InconsistentNaming
+        private static readonly MethodInfo unaryAddMethod;
+        private static readonly MethodInfo clientStreamingAddMethod;
+        private static readonly MethodInfo serverStreamingAddMethod;
+        private static readonly MethodInfo duplexStreamingAddMethod;
+
+        // ReSharper disable once IdentifierTypo
+        static GrpcMethodHelper()
+        {
+            buildMethod = typeof(GrpcMethodHelper).GetMethod("BuildMethod");
+            var methods = typeof(ServiceBinderBase).GetMethods().Where(p => p.Name == "AddMethod");
+            foreach (var method in methods)
+            {
+                var parameters = method.GetParameters();
+                if (parameters.Length != 2) continue;
+                if (parameters[1].ParameterType.Name.Contains("UnaryServerMethod"))
+                {
+                    unaryAddMethod = method;
+                }
+                else if (parameters[1].ParameterType.Name.Contains("ClientStreamingServerMethod"))
+                {
+                    clientStreamingAddMethod = method;
+                }
+                else if (parameters[1].ParameterType.Name.Contains("ServerStreamingServerMethod"))
+                {
+                    serverStreamingAddMethod = method;
+                }
+                else if (parameters[1].ParameterType.Name.Contains("DuplexStreamingServerMethod"))
+                {
+                    duplexStreamingAddMethod = method;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 自动注册服务方法
+        /// </summary>
+        /// <param name="srv"></param>
+        /// <param name="serviceBinder"></param>
+        /// <param name="package"></param>
+        /// <param name="serviceName"></param>
+        public static void AutoRegisterMethod(Type srv, ServiceBinderBase serviceBinder, string package = null, string serviceName = null)
+        {
+            var methods = srv.GetMethods(BindingFlags.Public | BindingFlags.Instance);
+            foreach (var method in methods)
+            {
+                if (!method.ReturnType.Name.StartsWith("Task")) continue;
+                var parameters = method.GetParameters();
+                if (parameters[parameters.Length-1].ParameterType != typeof(ServerCallContext) ||
+                    method.CustomAttributes.Any(x => x.AttributeType == typeof(NotGrpcMethodAttribute))) continue;
+
+                Type inputType = parameters[0].ParameterType;
+                Type inputType2 = parameters[1].ParameterType;
+                Type outputType = method.ReturnType.IsGenericType ? method.ReturnType.GenericTypeArguments[0] : method.ReturnType;
+
+                var addMethod = unaryAddMethod;
+                var serverMethodType = typeof(UnaryServerMethod<,>);
+                var methodType = MethodType.Unary;
+                var reallyInputType = inputType;
+                var reallyOutputType = outputType;
+
+                //非一元方法
+                if ((inputType.IsGenericType || inputType2.IsGenericType))
+                {
+                    if (inputType.Name == "IAsyncStreamReader`1")
+                    {
+                        reallyInputType = inputType.GenericTypeArguments[0];
+                        if (inputType2.Name == "IServerStreamWriter`1")//双向流
+                        {
+                            addMethod = duplexStreamingAddMethod;
+                            methodType = MethodType.DuplexStreaming;
+                            serverMethodType = typeof(DuplexStreamingServerMethod<,>);
+                            reallyOutputType = inputType2.GenericTypeArguments[0];
+                        }
+                        else//客户端流
+                        {
+                            addMethod = clientStreamingAddMethod;
+                            methodType = MethodType.ClientStreaming;
+                            serverMethodType = typeof(ClientStreamingServerMethod<,>);
+                        }
+                    }
+                    else if (inputType2.Name == "IServerStreamWriter`1")//服务端流
+                    {
+                        addMethod = serverStreamingAddMethod;
+                        methodType = MethodType.ServerStreaming;
+                        serverMethodType = typeof(ServerStreamingServerMethod<,>);
+                        reallyOutputType = inputType2.GenericTypeArguments[0];
+                    }
+                }
+                var buildMethodResult = buildMethod.MakeGenericMethod(reallyInputType, reallyOutputType)
+                    .Invoke(null, new object[] { srv, method.Name, package, serviceName, methodType });
+                Delegate serverMethodDelegate = method.CreateDelegate(serverMethodType
+                .MakeGenericType(reallyInputType, reallyOutputType), null);
+                addMethod.MakeGenericMethod(reallyInputType, reallyOutputType).Invoke(serviceBinder, new[] { buildMethodResult, serverMethodDelegate });
+            }
+        }
+
+        /// <summary>
+        /// 生成Grpc方法(CodeFirst方式)
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="srv"></param>
+        /// <param name="methodName"></param>
+        /// <param name="package"></param>
+        /// <param name="srvName"></param>
+        /// <param name="mType"></param>
+        /// <returns></returns>
+        public static Method<TRequest, TResponse> BuildMethod<TRequest, TResponse>(this Type srv,
+            string methodName, string package = null, string srvName = null, MethodType mType = MethodType.Unary)
+        {
+            var serviceName = srvName ??
+                              GrpcExtensionsOptions.Instance.GlobalService ??
+                              srv.Name;
+            var pkg = package ?? GrpcExtensionsOptions.Instance.GlobalPackage;
+            if (!string.IsNullOrWhiteSpace(pkg))
+            {
+                serviceName = $"{pkg}.{serviceName}";
+            }
+            #region 为生成proto收集信息
+            if (!(typeof(IGrpcBaseService).IsAssignableFrom(srv)) || GrpcExtensionsOptions.Instance.GenBaseServiceProtoEnable)
+            {
+                ProtoInfo.Methods.Add(new ProtoMethodInfo
+                {
+                    ServiceName = serviceName,
+                    MethodName = methodName,
+                    RequestName = typeof(TRequest).Name,
+                    ResponseName = typeof(TResponse).Name,
+                    MethodType = mType
+                });
+                ProtoGenerator.AddProto<TRequest>(typeof(TRequest).Name);
+                ProtoGenerator.AddProto<TResponse>(typeof(TResponse).Name);
+            }
+            #endregion
+            var request = Marshallers.Create<TRequest>((arg) => ProtobufExtensions.Serialize<TRequest>(arg), data => ProtobufExtensions.Deserialize<TRequest>(data));
+            var response = Marshallers.Create<TResponse>((arg) => ProtobufExtensions.Serialize<TResponse>(arg), data => ProtobufExtensions.Deserialize<TResponse>(data));
+            return new Method<TRequest, TResponse>(mType, serviceName, methodName, request, response);
+        }
+
+
+        /// <summary>
+        /// 绑定GrpcService的方法
+        /// </summary>
+        /// <param name="serviceBinder"></param>
+        /// <param name="service"></param>
+        public static void BindService(ServiceBinderBase serviceBinder, Type service)
+        {
+            if (typeof(IGrpcBaseService).IsAssignableFrom(service))
+            {
+                AutoRegisterMethod(service, serviceBinder, ServerConsts.BaseServicePackage, ServerConsts.BaseServiceName);
+            }
+            else
+            {
+                AutoRegisterMethod(service, serviceBinder);
+            }
+        }
+    }
+}

+ 189 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/ProviderServiceBinder.cs

@@ -0,0 +1,189 @@
+using Grpc.AspNetCore.Server.Model;
+using Grpc.Core;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.BaseService;
+using Grpc.Extension.BaseService.Model;
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Grpc.Extension.AspNetCore.Internal
+{
+    internal class ProviderServiceBinder<TService> : ServiceBinderBase where TService : class
+    {
+        private readonly ServiceMethodProviderContext<TService> _context;
+        private readonly Type _declaringType;
+        private readonly bool _isIGrpcService;
+        private readonly bool _isIGrpcBaseService;
+
+        internal ProviderServiceBinder(ServiceMethodProviderContext<TService> context, Type declaringType)
+        {
+            _context = context;
+            _declaringType = declaringType;
+            _isIGrpcService = typeof(IGrpcService).IsAssignableFrom(typeof(TService));
+            _isIGrpcBaseService = typeof(IGrpcBaseService).IsAssignableFrom(typeof(TService));
+        }
+
+        public override void AddMethod<TRequest, TResponse>(Method<TRequest, TResponse> method, ClientStreamingServerMethod<TRequest, TResponse> handler)
+        {
+            var (invoker, metadata) = CreateModelCore<ClientStreamingServerMethod<TService, TRequest, TResponse>>(
+                method.Name,
+                new[] { typeof(IAsyncStreamReader<TRequest>), typeof(ServerCallContext) });
+            if (_isIGrpcService)
+            {
+                _context.AddClientStreamingMethod<TRequest, TResponse>(method, metadata, invoker);
+            }
+            AddMetaMethod((new MetaMethodModel
+            {
+                FullName = method.FullName,
+                RequestType = typeof(TRequest),
+                ResponseType = typeof(TResponse),
+                ServiceType = typeof(TService),
+                Handler = invoker
+            })); 
+        }
+
+        public override void AddMethod<TRequest, TResponse>(Method<TRequest, TResponse> method, DuplexStreamingServerMethod<TRequest, TResponse> handler)
+        {
+            var (invoker, metadata) = CreateModelCore<DuplexStreamingServerMethod<TService, TRequest, TResponse>>(
+                method.Name,
+                new[] { typeof(IAsyncStreamReader<TRequest>), typeof(IServerStreamWriter<TResponse>), typeof(ServerCallContext) });
+            if (_isIGrpcService)
+            {
+                _context.AddDuplexStreamingMethod<TRequest, TResponse>(method, metadata, invoker);
+            }
+            AddMetaMethod((new MetaMethodModel
+            {
+                FullName = method.FullName,
+                RequestType = typeof(TRequest),
+                ResponseType = typeof(TResponse),
+                ServiceType = typeof(TService),
+                Handler = invoker
+            }));
+        }
+
+        public override void AddMethod<TRequest, TResponse>(Method<TRequest, TResponse> method, ServerStreamingServerMethod<TRequest, TResponse> handler)
+        {
+            var (invoker, metadata) = CreateModelCore<ServerStreamingServerMethod<TService, TRequest, TResponse>>(
+                method.Name,
+                new[] { typeof(TRequest), typeof(IServerStreamWriter<TResponse>), typeof(ServerCallContext) });
+            if (_isIGrpcService)
+            {
+                _context.AddServerStreamingMethod<TRequest, TResponse>(method, metadata, invoker);
+            }
+            AddMetaMethod((new MetaMethodModel
+            {
+                FullName = method.FullName,
+                RequestType = typeof(TRequest),
+                ResponseType = typeof(TResponse),
+                ServiceType = typeof(TService),
+                Handler = invoker
+            }));
+        }
+
+        public override void AddMethod<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryServerMethod<TRequest, TResponse> handler)
+        {
+            var (invoker, metadata) = CreateModelCore<UnaryServerMethod<TService, TRequest, TResponse>>(
+                method.Name,
+                new[] { typeof(TRequest), typeof(ServerCallContext) });
+            if (_isIGrpcService)
+            {
+                _context.AddUnaryMethod<TRequest, TResponse>(method, metadata, invoker);
+            }
+            AddMetaMethod((new MetaMethodModel
+            {
+                FullName = method.FullName,
+                RequestType = typeof(TRequest),
+                ResponseType = typeof(TResponse),
+                ServiceType =  typeof(TService),
+                Handler = invoker
+            }));
+        }
+
+        private Delegate GetOrCreateHandler<TDelegate>(Delegate handler ,string methodName, Type[] methodParameters)
+        {
+            if (handler != null) return handler;
+            //创建Handler
+            var handlerMethod = GetMethod(methodName, methodParameters);
+            if (handlerMethod == null)
+            {
+                throw new InvalidOperationException($"Could not find '{methodName}' on {typeof(TService)}.");
+            }
+            handler = handlerMethod.CreateDelegate(typeof(TDelegate),null);
+
+            return handler;
+        }
+
+        private (TDelegate invoker, List<object> metadata) CreateModelCore<TDelegate>(string methodName, Type[] methodParameters) where TDelegate : Delegate
+        {
+            var handlerMethod = GetMethod(methodName, methodParameters);
+
+            if (handlerMethod == null)
+            {
+                throw new InvalidOperationException($"Could not find '{methodName}' on {typeof(TService)}.");
+            }
+
+            var invoker = (TDelegate)Delegate.CreateDelegate(typeof(TDelegate), handlerMethod);
+
+            var metadata = new List<object>();
+            // Add type metadata first so it has a lower priority
+            metadata.AddRange(typeof(TService).GetCustomAttributes(inherit: true));
+            // Add method metadata last so it has a higher priority
+            metadata.AddRange(handlerMethod.GetCustomAttributes(inherit: true));
+
+            // Accepting CORS preflight means gRPC will allow requests with OPTIONS + preflight headers.
+            // If CORS middleware hasn't been configured then the request will reach gRPC handler.
+            // gRPC will return 405 response and log that CORS has not been configured.
+            metadata.Add(new HttpMethodMetadata(new[] { "POST" }, acceptCorsPreflight: true));
+
+            return (invoker, metadata);
+        }
+
+        private MethodInfo? GetMethod(string methodName, Type[] methodParameters)
+        {
+            Type? currentType = typeof(TService);
+            while (currentType != null)
+            {
+                var matchingMethod = currentType.GetMethod(
+                    methodName,
+                    BindingFlags.Public | BindingFlags.Instance,
+                    binder: null,
+                    types: methodParameters,
+                    modifiers: null);
+
+                if (matchingMethod == null)
+                {
+                    return null;
+                }
+                if (_isIGrpcService)
+                {
+                    return matchingMethod;
+                }
+                // Validate that the method overrides the virtual method on the base service type.
+                // If there is a method with the same name it will hide the base method. Ignore it,
+                // and continue searching on the base type.
+                if (matchingMethod.IsVirtual)
+                {
+                    var baseDefinitionMethod = matchingMethod.GetBaseDefinition();
+                    if (baseDefinitionMethod != null && baseDefinitionMethod.DeclaringType == _declaringType)
+                    {
+                        return matchingMethod;
+                    }
+                }
+
+                currentType = currentType.BaseType;
+            }
+
+            return null;
+        }
+
+        private void AddMetaMethod(MetaMethodModel model)
+        {
+            if (_isIGrpcBaseService) return;
+
+            MetaModel.Methods.Add(model);
+        }
+    }
+}

+ 78 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Internal/RegisterServiceHosted.cs

@@ -0,0 +1,78 @@
+using Grpc.Extension.Abstract.Discovery;
+using Grpc.Extension.BaseService.Model;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Extension.AspNetCore;
+using Microsoft.Extensions.Options;
+using Grpc.Extension.Abstract.Model;
+using Grpc.Extension.Common;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using System.Linq;
+
+namespace Grpc.Extension.AspNetCore.Internal
+{
+    public class RegisterServiceHosted : IHostedService
+    {
+        private readonly IServiceRegister _serviceRegister;
+        private readonly IServer _server;
+        private readonly GrpcServerOptions _grpcServerOptions;
+        private readonly IHostApplicationLifetime _hostApplicationLifetime;
+        private readonly ILogger _logger;
+
+        public RegisterServiceHosted(IServiceRegister serviceRegister, IServer server, IOptions<GrpcServerOptions> grpcServerOptions,
+            IHostApplicationLifetime hostApplicationLifetime, ILogger<RegisterServiceHosted> logger)
+        {
+            _serviceRegister = serviceRegister;
+            _server = server;
+            _grpcServerOptions = grpcServerOptions.Value;
+            _hostApplicationLifetime = hostApplicationLifetime;
+            _logger = logger;
+        }
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            if(_grpcServerOptions.EnableDiscovery)
+                _hostApplicationLifetime.ApplicationStarted.Register(Start);
+
+            return Task.CompletedTask;
+        }
+
+        public void Start()
+        {
+            var serverAddressesFeature = _server.Features?.Get<IServerAddressesFeature>();
+            if (serverAddressesFeature == null || serverAddressesFeature.Addresses.Count == 0)
+            {
+                _logger.LogError("can not found IServerAddressesFeature in IServer,can not register service.");
+                return;
+            }
+            //添加服务IPAndPort
+            var ipPort = NetHelper.GetIPAndPort(_grpcServerOptions.ServiceAddress);
+            var serverAddress = BindingAddress.Parse(serverAddressesFeature.Addresses.First());
+
+            MetaModel.StartTime = DateTime.Now;
+            MetaModel.Ip = ipPort.Item1;
+            MetaModel.Port = serverAddress.Port;
+            Console.WriteLine($"server listening {MetaModel.Ip}:{MetaModel.Port}");
+            //使用BaseServices
+            Console.WriteLine($"use {_serviceRegister.GetType().Name} register");
+            Console.WriteLine($"    DiscoveryUrl:{_grpcServerOptions.DiscoveryUrl}");
+            Console.WriteLine($"    ServiceName:{_grpcServerOptions.DiscoveryServiceName}");
+            var registerModel = _grpcServerOptions.ToJson().FromJson<ServiceRegisterModel>();
+            registerModel.ServiceIp = MetaModel.Ip;
+            registerModel.ServicePort = MetaModel.Port;
+            _serviceRegister.RegisterService(registerModel);
+        }
+
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            if(_grpcServerOptions.EnableDiscovery)
+                _serviceRegister.DeregisterService();
+
+            return Task.CompletedTask;
+        }
+    }
+}

+ 63 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/Options/GrpcServerOptions.cs

@@ -0,0 +1,63 @@
+using Grpc.Extension.Abstract.Model;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.AspNetCore
+{
+    /// <summary>
+    /// GrpcServerOptions
+    /// </summary>
+    public class GrpcServerOptions
+    {
+        /// <summary>
+        /// Grpc服务地址(192.168.*.*)
+        /// </summary>
+        public string ServiceAddress { get; set; }
+
+        /// <summary>
+        /// 是否启用服务注册和服务发现
+        /// </summary>
+        public bool EnableDiscovery { get; set; } = true;
+
+        /// <summary>
+        /// 服务注册地址(http://192.168.8.6:8500)
+        /// </summary>
+        public string DiscoveryUrl { get; set; }
+
+        /// <summary>
+        /// 服务注册名
+        /// </summary>
+        public string DiscoveryServiceName { get; set; }
+
+        /// <summary>
+        /// 服务注册Tags(可用于版本标记)
+        /// </summary>
+        public string DiscoveryServiceTags { get; set; }
+
+        /// <summary>
+        /// 服务TTL(秒)
+        /// </summary>
+        public int DiscoveryTTLInterval { get; set; } = 10;
+
+        /// <summary>
+        /// 默认错误码
+        /// </summary>
+        public int DefaultErrorCode
+        {
+            get { return GrpcErrorCode.DefaultErrorCode; }
+            set { GrpcErrorCode.DefaultErrorCode = value; }
+        }
+
+        /// <summary>
+        /// JaegerOptions
+        /// </summary>
+        public JaegerOptions Jaeger { get; set; }
+
+        /// <summary>
+        /// Grpc客户端调用超时时间(单位:秒)
+        /// </summary>
+        public double GrpcCallTimeOut { get; set; } = 10;
+    }
+
+}

+ 105 - 0
TEAMModelOS.SDK/Module/Grpc/AspNetCore/ServiceCollectionExtensions.cs

@@ -0,0 +1,105 @@
+using Grpc.AspNetCore.Server;
+using Grpc.AspNetCore.Server.Model;
+using Grpc.Extension;
+using Grpc.Extension.AspNetCore;
+using Grpc.Extension.Client;
+using Grpc.Extension.Interceptors;
+using Grpc.Extension.AspNetCore.Internal;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using OpenTracing;
+using System;
+
+namespace Grpc.Extension.AspNetCore
+{
+    public static class ServiceCollectionExtensions
+    {
+        /// <summary>
+        /// 添加Grpc扩展
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="conf"></param>
+        public static void AddGrpcExtensions(this IServiceCollection services, IConfiguration conf) => AddGrpcExtensions(services, conf, null);
+
+        /// <summary>
+        /// 添加Grpc扩展
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="conf"></param>
+        /// <param name="configureOptions"></param>
+        /// <returns></returns>
+        public static IGrpcServerBuilder AddGrpcExtensions(this IServiceCollection services, IConfiguration conf, Action<GrpcServiceOptions> configureOptions)
+        {
+            //注入配制
+            services.Configure<GrpcServerOptions>(conf.GetSection("GrpcServer"));
+            //AddGrpc
+            var builder = services.AddGrpc(options => {
+                options.Interceptors.Add<MonitorInterceptor>();
+                options.Interceptors.Add<ThrottleInterceptor>();
+                //Jaeger
+                options.AddJaegerInterceptor(conf);
+                //执行配制
+                configureOptions?.Invoke(options);
+            });
+            //ServiceMethodProvider
+            services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IServiceMethodProvider<>), typeof(BinderServiceMethodProvider<>)));
+            //添加Jaeger
+            services.AddJaeger(conf);
+            //添加GrpcClient扩展
+            services.AddGrpcClientExtensions(conf);
+            //注册到服务发现
+            services.AddHostedService<RegisterServiceHosted>();
+            return builder;
+        }
+
+        /// <summary>
+        /// 添加Jaeger
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="conf"></param>
+        /// <returns></returns>
+        private static IServiceCollection AddJaeger(this IServiceCollection services, IConfiguration conf)
+        {
+            var key = "GrpcServer:Jaeger";
+            var jaegerOptions = conf.GetSection(key).Get<JaegerOptions>();
+            if (jaegerOptions == null || jaegerOptions.Enable == false)
+                return services;
+
+            //jaeger
+            services.AddSingleton<ITracer>(sp => {
+                var options = sp.GetService<IOptions<GrpcServerOptions>>().Value.Jaeger;
+                var serviceName = options.ServiceName;
+                var tracer = new Jaeger.Tracer.Builder(serviceName)
+               .WithLoggerFactory(sp.GetService<ILoggerFactory>())
+               .WithSampler(new Jaeger.Samplers.ConstSampler(true))
+               .WithReporter(new Jaeger.Reporters.RemoteReporter.Builder()
+                   .WithFlushInterval(TimeSpan.FromSeconds(5))
+                   .WithMaxQueueSize(5)
+                   .WithSender(new Jaeger.Senders.UdpSender(jaegerOptions.AgentIp, jaegerOptions.AgentPort, 1024 * 5)).Build())
+               .Build();
+                return tracer;
+            });
+
+            return services;
+        }
+
+        /// <summary>
+        /// 添加jaeger中间件 
+        /// </summary>
+        /// <param name="grpcServiceOptions"></param>
+        /// <param name="conf"></param>
+        private static void AddJaegerInterceptor(this GrpcServiceOptions grpcServiceOptions, IConfiguration conf)
+        {
+            var key = "GrpcServer:Jaeger";
+            var jaegerOptions = conf.GetSection(key).Get<JaegerOptions>();
+            if (jaegerOptions == null || jaegerOptions.Enable == false)
+                return;
+
+            //添加jaeger中间件
+            grpcServiceOptions.Interceptors.Add<JaegerTracingInterceptor>();
+        }
+    }
+}

+ 97 - 0
TEAMModelOS.SDK/Module/Grpc/Client/GrpcClientApp.cs

@@ -0,0 +1,97 @@
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Common.Internal;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using OpenTracing;
+using OpenTracing.Util;
+using System;
+
+namespace Grpc.Extension.Client
+{
+    /// <summary>
+    /// GrpcClient启动类
+    /// </summary>
+    public class GrpcClientApp
+    {
+        private readonly GrpcClientOptions _grpcClientOptions;
+        private readonly ILoggerFactory _loggerFactory;
+
+        /// <summary>
+        /// GrpcClientApp
+        /// </summary>
+        /// <param name="serviceProvider"></param>
+        /// <param name="grpcClientOptions"></param>
+        /// <param name="loggerFactory"></param>
+        public GrpcClientApp(IServiceProvider serviceProvider, IOptions<GrpcClientOptions> grpcClientOptions, ILoggerFactory loggerFactory)
+        {
+            ServiceProviderAccessor.SetServiceProvider(serviceProvider);
+            _grpcClientOptions = grpcClientOptions.Value;
+            _loggerFactory = loggerFactory;
+
+            this.UseLoggerFactory()//使用LoggerFactory
+                .UseJaeger();
+
+        }
+
+        /// <summary>
+        /// 注入Grpc,Discovery配制
+        /// </summary>
+        /// <param name="options"></param>
+        /// <returns></returns>
+        public GrpcClientApp UseGrpcOptions(Action<GrpcClientOptions> options)
+        {
+            options(_grpcClientOptions);
+            return this;
+        }
+
+        /// <summary>
+        /// 使用LoggerFactory
+        /// </summary>
+        /// <returns></returns>
+        private GrpcClientApp UseLoggerFactory()
+        {
+            var _logger = _loggerFactory.CreateLogger<GrpcClientApp>();
+            var _loggerAccess = _loggerFactory.CreateLogger("grpc.access");
+
+            LoggerAccessor.Instance.LoggerError += (ex, type) => _logger.LogError(ex.ToString());
+            LoggerAccessor.Instance.LoggerMonitor += (msg, type) => _loggerAccess.LogInformation(msg);
+
+            return this;
+        }
+
+        /// <summary>
+        /// 配制日志(默认使用LoggerFactory)
+        /// </summary>
+        /// <param name="action"></param>
+        /// <returns></returns>
+        public GrpcClientApp UseLogger(Action<LoggerAccessor> action)
+        {
+            action(LoggerAccessor.Instance);
+            return this;
+        }
+
+        /// <summary>
+        /// 有Jaeger配制就使用Jaeger
+        /// </summary>
+        private void UseJaeger()
+        {
+            var jaeger = _grpcClientOptions.Jaeger;
+            if (jaeger?.CheckConfig() == true)
+            {
+                var tracer = ServiceProviderAccessor.GetService<ITracer>();
+                if (tracer != null) GlobalTracer.Register(tracer);
+            }
+        }
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public void Run()
+        {
+            //检查服务发现配制
+            if (string.IsNullOrWhiteSpace(_grpcClientOptions.DiscoveryUrl))
+                throw new ArgumentException("GrpcClient:DiscoveryUrl is null");
+        }
+    }
+}

+ 51 - 0
TEAMModelOS.SDK/Module/Grpc/Client/GrpcClientManager.cs

@@ -0,0 +1,51 @@
+using Grpc.Extension.Common;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Microsoft.Extensions.DependencyInjection;
+using Grpc.Core.Interceptors;
+using System.Linq;
+using Grpc.Core;
+using Grpc.Extension.Common.Internal;
+using Grpc.Extension.Client.Interceptors;
+using Grpc.Extension.Client.Internal;
+
+namespace Grpc.Extension.Client
+{
+    /// <summary>
+    /// GrpcClient,用于批量调用
+    /// </summary>
+    public class GrpcClientManager
+    {
+        private IEnumerable<ClientInterceptor> _clientInterceptors;
+
+        /// <summary>
+        /// GrpcClient
+        /// </summary>
+        /// <param name="serviceProvider"></param>
+        /// <param name="clientInterceptors"></param>
+        public GrpcClientManager(IServiceProvider serviceProvider, IEnumerable<ClientInterceptor> clientInterceptors)
+        {
+            ServiceProviderAccessor.SetServiceProvider(serviceProvider);
+            this._clientInterceptors = clientInterceptors;
+        }
+
+        /// <summary>
+        /// 获取GrpcClient,用于批量调用
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public T GetGrpcClient<T>() where T : ClientBase<T>
+        {
+            var channelManager = ServiceProviderAccessor.GetService<ChannelPool>();
+            var bindFlags = BindingFlags.Static | BindingFlags.NonPublic;
+            var grpcServiceName = typeof(T).DeclaringType.GetFieldValue<string>("__ServiceName", bindFlags);
+
+            var channel = channelManager.GetChannel(grpcServiceName);
+            var callInvoker = channel.Intercept(_clientInterceptors.ToArray());
+            var client = Activator.CreateInstance(typeof(T), callInvoker);
+
+            return client as T;
+        }
+    }
+}

+ 66 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/CientCallTimeout.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+
+namespace Grpc.Extension.Client.Interceptors
+{
+    /// <summary>
+    /// 客户端超时拦截器
+    /// </summary>
+    internal class ClientCallTimeout : ClientInterceptor
+    {
+        private double _callTimeOutSecond;
+
+        /// <summary>
+        /// 客户端超时拦截器
+        /// </summary>
+        /// <param name="callTimeOutSecond"></param>
+        public ClientCallTimeout(double callTimeOutSecond)
+        {
+            this._callTimeOutSecond = callTimeOutSecond;
+        }
+
+        /// <summary>
+        /// 同步调用
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, Interceptor.BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            var callOptions = SetDeadline(context.Options);
+            var newContext = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, callOptions);
+            return continuation(request, newContext);
+        }
+      
+        /// <summary>
+        /// 异步调用
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, Interceptor.AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            var callOptions = SetDeadline(context.Options);
+            var newContext = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, callOptions);
+            return continuation(request, newContext);
+        }
+
+        private CallOptions SetDeadline(CallOptions callOptions)
+        {
+            if (callOptions.Deadline == null)
+            {
+                callOptions = callOptions.WithDeadline(DateTime.UtcNow.AddSeconds(_callTimeOutSecond));
+            }
+            return callOptions;
+        }
+    }
+}

+ 79 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/ClientJaegerTracingInterceptor.cs

@@ -0,0 +1,79 @@
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+using OpenTracing.Util;
+using System;
+using Grpc.Extension.Common;
+using System.Linq;
+using OpenTracing;
+using Grpc.Extension.Abstract;
+
+namespace Grpc.Extension.Client.Interceptors
+{
+    internal class ClientJaegerTracingInterceptor : ClientInterceptor
+    {
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            var tracer = GlobalTracer.Instance;
+            var method = $"{context.Method.ServiceName}/{context.Method.Name}";
+            var span = tracer.BuildSpan(method).AsChildOf(tracer.ActiveSpan).WithTag("Request", request?.ToJson() ?? "").Start();
+            context = SetJaegerHeader(context, span);
+            try
+            {
+                return continuation(request, context);
+            }
+            catch (Exception ex)
+            {
+                span.SetTag("Error", ex.ToString());
+                throw;
+            }
+            finally
+            {
+                span.Finish();
+            }
+        }
+
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            var tracer = GlobalTracer.Instance;
+            var method = $"{context.Method.ServiceName}/{context.Method.Name}";
+            var span = tracer.BuildSpan(method).AsChildOf(tracer.ActiveSpan).WithTag("Request", request?.ToJson() ?? "").Start();
+            context = SetJaegerHeader(context, span);
+            try
+            {
+                return continuation(request, context);
+            }
+            catch (Exception ex)
+            {
+                span.SetTag("Error", ex.ToString());
+                throw;
+            }
+            finally
+            {
+                span.Finish();
+            }
+        }
+
+        private ClientInterceptorContext<TRequest, TResponse> SetJaegerHeader<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, ISpan span)
+            where TRequest : class
+            where TResponse : class
+        {
+            var header = context.Options.Headers?.Where(p => p.Key == Consts.OpenTraceId).FirstOrDefault();
+            if (header == null)
+            {
+                var metaEntry = new Metadata.Entry(Consts.OpenTraceId, span.Context.ToString());
+                if (context.Options.Headers == null)
+                {
+                    var meta = new Metadata();
+                    meta.Add(metaEntry);
+                    var callOptions = context.Options.WithHeaders(meta);
+                    context = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, callOptions);
+                }
+                else
+                {
+                    context.Options.Headers.Add(metaEntry);
+                }
+            }
+            return context;
+        }
+    }
+}

+ 107 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/Client/ClientMonitorInterceptor.cs

@@ -0,0 +1,107 @@
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Abstract.Model;
+using Grpc.Extension.Common;
+using Grpc.Extension.Common.Internal;
+using System;
+using System.Linq;
+
+namespace Grpc.Extension.Client.Interceptors
+{
+    internal class ClientMonitorInterceptor : ClientInterceptor
+    {
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            context = SetTraceIdHeader(context);
+            var model = new MonitorModel
+            {
+                ClientIp = context.Host,
+                RequestUrl = context.Method.FullName,
+                RequestData = request?.ToJson(),
+                RequestHeaders = context.Options.Headers.ToDictionary(p => p.Key, p => p.Value),
+                TraceId = context.Options.Headers?.Where(p => p.Key == Consts.TraceId).FirstOrDefault()?.Value
+            };
+            try
+            {
+                var result = continuation(request, context);
+                var data = result.GetAwaiter().GetResult();
+                //model.ResponseData = data.ToJson();
+                model.Status = "ok";
+                model.ResponseTime = DateTime.Now;
+                return result;
+            }
+            catch (Exception ex)
+            {
+                ex.Data.Add("Request", model);
+                model.Status = "error";
+                model.ResponseTime = DateTime.Now;
+                model.Exception = ex.GetFlatException();
+                LoggerAccessor.Instance.OnLoggerError(ex, LogType.ClientLog);
+                throw ex;
+            }
+            finally
+            {
+                LoggerAccessor.Instance.OnLoggerMonitor(model.ToJson(), LogType.ClientLog);
+            }
+        }
+
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            context = SetTraceIdHeader(context);
+            var model = new MonitorModel
+            {
+                ClientIp = context.Host,
+                RequestUrl = context.Method.FullName,
+                RequestData = request?.ToJson(),
+                RequestHeaders = context.Options.Headers.ToDictionary(p => p.Key, p => p.Value),
+                TraceId = context.Options.Headers?.Where(p => p.Key == Consts.TraceId).FirstOrDefault()?.Value
+            };
+            try
+            {
+                var result = continuation(request, context);
+                model.Status = "ok";
+                model.ResponseTime = DateTime.Now;
+                return result;
+            }
+            catch (Exception ex)
+            {
+                ex.Data.Add("Request", model);
+                model.Status = "error";
+                model.ResponseTime = DateTime.Now;
+                model.Exception = ex.GetFlatException();
+                LoggerAccessor.Instance.OnLoggerError(ex, LogType.ClientLog);
+                throw ex;
+            }
+            finally
+            {
+                LoggerAccessor.Instance.OnLoggerMonitor(model.ToJson(), LogType.ClientLog);
+            }
+        }
+
+        private ClientInterceptorContext<TRequest, TResponse> SetTraceIdHeader<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class
+        {
+            var header = context.Options.Headers?.Where(p => p.Key == Consts.TraceId).FirstOrDefault();
+            if (header == null)
+            {
+                var serverHeader = ServerCallContextAccessor.Current?.RequestHeaders.Where(p => p.Key == Consts.TraceId).FirstOrDefault();
+                var traceId = serverHeader == null ? Guid.NewGuid().ToString() : serverHeader.Value;
+                header = new Metadata.Entry(Consts.TraceId, traceId);
+                if (context.Options.Headers == null)
+                {
+                    var meta = new Metadata();
+                    meta.Add(header);
+                    var callOptions = context.Options.WithHeaders(meta);
+                    context = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, callOptions);
+                }
+                else
+                {
+                    context.Options.Headers.Add(header);
+                }
+            }
+            return context;
+        }
+    }
+}

+ 83 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/ClientInterceptor.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+
+namespace Grpc.Extension.Client.Interceptors
+{
+    /// <summary>
+    /// 客户端拦截器
+    /// </summary>
+    public class ClientInterceptor : Interceptor
+    {
+        /// <summary>
+        /// 同步调用
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, Interceptor.BlockingUnaryCallContinuation<TRequest, TResponse> continuation) 
+        {
+            return continuation(request, context);
+        }
+      
+        /// <summary>
+        /// 异步调用
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, Interceptor.AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// 异步客户端流请求
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+        {
+            return continuation(context);
+        }
+
+        /// <summary>
+        /// 异步服务端流返回
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// 异步双向流
+        /// </summary>
+        /// <typeparam name="TRequest"></typeparam>
+        /// <typeparam name="TResponse"></typeparam>
+        /// <param name="context"></param>
+        /// <param name="continuation"></param>
+        /// <returns></returns>
+        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
+        {
+            return continuation(context);
+        }
+   
+    }
+}

+ 47 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Interceptors/InterceptorCallInvoker.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+using Grpc.Extension.Client.Internal;
+
+namespace Grpc.Extension.Client.Interceptors
+{
+    /// <summary>
+    /// 客户端中间件的CallInvoker
+    /// </summary>
+    internal class InterceptorCallInvoker : CallInvoker
+    {
+        private CallInvoker _interceptorCallInvoker;
+        public InterceptorCallInvoker(AutoChannelCallInvoker autoChannelCallInvoker, IEnumerable<ClientInterceptor> clientInterceptors)
+        {
+            _interceptorCallInvoker = autoChannelCallInvoker.Intercept(clientInterceptors.ToArray());
+        }
+
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return _interceptorCallInvoker.BlockingUnaryCall(method, host, options, request);
+        }
+
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return _interceptorCallInvoker.AsyncUnaryCall(method, host, options, request);
+        }
+
+        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return _interceptorCallInvoker.AsyncServerStreamingCall(method, host, options, request);
+        }
+
+        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            return _interceptorCallInvoker.AsyncClientStreamingCall(method, host, options);
+        }
+
+        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            return _interceptorCallInvoker.AsyncDuplexStreamingCall(method, host, options);
+        }
+    }
+}

+ 82 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Internal/AutoChannelCallInvoker.cs

@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.ServiceModel.Channels;
+using System.Text;
+using Grpc.Core;
+
+namespace Grpc.Extension.Client.Internal
+{
+    /// <summary>
+    /// 自动负载Channel的CallInvoker
+    /// </summary>
+    internal class AutoChannelCallInvoker : CallInvoker
+    {
+        private ChannelPool _channelManager;
+
+        /// <summary>
+        /// 自动负载Channel的CallInvoker
+        /// </summary>
+        public AutoChannelCallInvoker(ChannelPool channelManager)
+        {
+            this._channelManager = channelManager;
+        }
+
+        /// <summary>
+        /// Invokes a simple remote call in a blocking fashion.
+        /// </summary>
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            var call = CreateCall(method, host, options);
+            return Calls.BlockingUnaryCall(call, request);
+        }
+
+        /// <summary>
+        /// Invokes a simple remote call asynchronously.
+        /// </summary>
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            var call = CreateCall(method, host, options);
+            return Calls.AsyncUnaryCall(call, request);
+        }
+
+        /// <summary>
+        /// Invokes a server streaming call asynchronously.
+        /// In server streaming scenario, client sends on request and server responds with a stream of responses.
+        /// </summary>
+        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            var call = CreateCall(method, host, options);
+            return Calls.AsyncServerStreamingCall(call, request);
+        }
+
+        /// <summary>
+        /// Invokes a client streaming call asynchronously.
+        /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
+        /// </summary>
+        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            var call = CreateCall(method, host, options);
+            return Calls.AsyncClientStreamingCall(call);
+        }
+
+        /// <summary>
+        /// Invokes a duplex streaming call asynchronously.
+        /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
+        /// The response stream is completely independent and both side can be sending messages at the same time.
+        /// </summary>
+        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            var call = CreateCall(method, host, options);
+            return Calls.AsyncDuplexStreamingCall(call);
+        }
+
+        /// <summary>Creates call invocation details for given method.</summary>
+        protected virtual CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+                where TRequest : class
+                where TResponse : class
+        {
+            var channel = _channelManager.GetChannel(method.ServiceName);
+            return new CallInvocationDetails<TRequest, TResponse>(channel, method, host, options);
+        }
+    }
+}

+ 170 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Internal/ChannelPool.cs

@@ -0,0 +1,170 @@
+using Grpc.Core;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Caching.Memory;
+using Grpc.Extension.Abstract.Model;
+using Grpc.Extension.Abstract.Discovery;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Client.Model;
+using Microsoft.Extensions.Options;
+
+namespace Grpc.Extension.Client.Internal
+{
+    /// <summary>
+    /// Channel统一管理
+    /// </summary>
+    internal class ChannelPool
+    {
+        private ConcurrentDictionary<string, ChannelInfo> _channels = new ConcurrentDictionary<string, ChannelInfo>();
+        private IServiceDiscovery _serviceDiscovery;
+        private ILoadBalancer _loadBalancer;
+        private IMemoryCache _memoryCache;
+        private GrpcClientOptions _grpcClientOptions;
+
+        /// <summary>
+        /// Channel统一管理
+        /// </summary>
+        /// <param name="serviceDiscovery"></param>
+        /// <param name="loadBalancer"></param>
+        /// <param name="memoryCache"></param>
+        /// <param name="grpcClientOptions"></param>
+        public ChannelPool(IServiceDiscovery serviceDiscovery, ILoadBalancer loadBalancer,IMemoryCache memoryCache, IOptions<GrpcClientOptions> grpcClientOptions)
+        {
+            this._serviceDiscovery = serviceDiscovery;
+            this._loadBalancer = loadBalancer;
+            this._memoryCache = memoryCache;
+            this._grpcClientOptions = grpcClientOptions.Value;
+        }
+
+        internal static List<ChannelConfig> Configs { get; set; } = new List<ChannelConfig>();
+
+        /// <summary>
+        /// 根据客户端代理类型获取channel
+        /// </summary>
+        public Channel GetChannel(string grpcServiceName)
+        {
+            var config = Configs?.FirstOrDefault(q => q.GrpcServiceName == grpcServiceName?.Trim());
+            if (config == null)
+            {
+                throw new InternalException(GrpcErrorCode.Internal, $"{grpcServiceName ?? ""} client has not config,please call AddGrpcClient method");
+            }
+            if (config.UseDirect)
+            {
+                return GetChannelCore(config.DirectEndpoint,config);
+            }
+            else//from discovery
+            {
+                var discoveryUrl = !string.IsNullOrWhiteSpace(config.DiscoveryUrl) ? config.DiscoveryUrl : _grpcClientOptions.DiscoveryUrl;
+                var endPoint = GetEndpoint(config.DiscoveryServiceName, discoveryUrl, config.DiscoveryServiceTag);
+                return GetChannelCore(endPoint,config);
+            }
+        }
+
+        /// <summary>
+        /// 根据服务名称返回服务地址
+        /// </summary>
+        private string GetEndpoint(string serviceName, string dicoveryUrl, string serviceTag)
+        {
+            //获取健康的endpoints
+            var isCache = true;
+            var healthEndpoints = _memoryCache.GetOrCreate(serviceName, cacheEntry =>
+            {
+                isCache = false;
+                cacheEntry.SetAbsoluteExpiration(TimeSpan.FromSeconds(_grpcClientOptions.ServiceAddressCacheTime));
+                return _serviceDiscovery.GetEndpoints(serviceName, dicoveryUrl, serviceTag);
+            });
+            if (healthEndpoints == null || healthEndpoints.Count == 0)
+            {
+                throw new InternalException(GrpcErrorCode.Internal,$"get endpoints from discovery of {serviceName} is null");
+            }
+            //只有重新拉取了健康结点才需要去关闭不健康的Channel
+            if (isCache == false) ShutdownErrorChannel(healthEndpoints, serviceName);
+
+            return _loadBalancer.SelectEndpoint(serviceName, healthEndpoints);
+        }
+
+        private Channel GetChannelCore(string endpoint,ChannelConfig config)
+        {
+            //获取channel,不存在就添加
+            var channel = _channels.GetOrAdd(endpoint, (key) => CreateChannel(key,config)).Channel;
+            //检查channel状态
+            if (channel.State != ChannelState.Ready)
+            {
+                //状态异常就关闭后重建
+                channel.ShutdownAsync();
+                _channels.TryRemove(config.DiscoveryServiceName, out var tmp);
+                //新增或者修改channel
+                return _channels.AddOrUpdate(endpoint, (key) => CreateChannel(key, config), (key, value) => CreateChannel(key,config)).Channel;
+            }
+            else
+            {
+                return channel;
+            }
+        }
+
+        private ChannelInfo CreateChannel(string endPoint, ChannelConfig config)
+        {
+            var channel = new Channel(endPoint, ChannelCredentials.Insecure, config.ChannelOptions);
+
+            var tryCount = 0;//重试计数
+            //检查channel状态
+            while (channel.State != ChannelState.Ready)
+            {
+                try
+                {
+                    channel.ConnectAsync(DateTime.UtcNow.AddSeconds(1)).Wait();
+                }
+                catch (Exception ex)
+                {
+                    tryCount++;
+                    var exMsg = $"create channel for {config.DiscoveryServiceName} service failed {tryCount},status:{channel.State},endpoint:{endPoint}";
+                    var exeption = new InternalException(GrpcErrorCode.Internal, exMsg, ex);
+                    if (tryCount > 2)
+                    {
+                        throw exeption;
+                    }
+                    else
+                    {
+                        LoggerAccessor.Instance.OnLoggerError(exeption, LogType.ClientLog);
+                    }
+                    //重新获取Endpoint,故障转移
+                    if (!config.UseDirect)
+                    {
+                        endPoint = GetEndpoint(config.DiscoveryServiceName, config.DiscoveryUrl, config.DiscoveryServiceTag);
+                        channel = new Channel(endPoint, ChannelCredentials.Insecure);
+                    }
+                }
+            }
+            return new ChannelInfo() { DiscoveryServiceName= config.DiscoveryServiceName,Channel = channel};
+        }
+
+        /// <summary>
+        /// 关闭不健康Channel
+        /// </summary>
+        /// <param name="healthEndpoints"></param>
+        /// <param name="serviceName"></param>
+        private void ShutdownErrorChannel(List<string> healthEndpoints,string serviceName)
+        {
+            //获取错误的channel
+            var errorChannel = _channels.Where(p => p.Value.DiscoveryServiceName == serviceName &&
+                                                !healthEndpoints.Contains(p.Key)).ToList();
+            //关闭并删除错误的channel
+            foreach (var channel in errorChannel)
+            {
+                channel.Value.Channel.ShutdownAsync();
+                _channels.TryRemove(channel.Key, out var tmp);
+            }
+        }
+
+        /// <summary>
+        /// 关闭所有Channel
+        /// </summary>
+        public void Shutdown()
+        {
+            _channels.Select(q => q.Value).ToList().ForEach(q => q.Channel.ShutdownAsync().Wait());
+            _channels.Clear();
+        }
+    }
+}

+ 26 - 0
TEAMModelOS.SDK/Module/Grpc/Client/LoadBalancer/RandomLoadBalancer.cs

@@ -0,0 +1,26 @@
+using Grpc.Extension.Abstract;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Grpc.Extension.Client.LoadBalancer
+{
+    /// <summary>
+    /// 随机负载
+    /// </summary>
+    public class RandomLoadBalancer : ILoadBalancer
+    {
+        /// <summary>
+        /// 随机获取Endpoint
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <param name="endpoints"></param>
+        /// <returns></returns>
+        public string SelectEndpoint(string serviceName, List<string> endpoints)
+        {
+            endpoints = endpoints.OrderBy(q => Guid.NewGuid()).ToList();
+            return endpoints.FirstOrDefault();
+        }
+    }
+}

+ 33 - 0
TEAMModelOS.SDK/Module/Grpc/Client/LoadBalancer/RoundLoadBalancer.cs

@@ -0,0 +1,33 @@
+using Grpc.Extension.Abstract;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Grpc.Extension.Client.LoadBalancer
+{
+    /// <summary>
+    /// 轮询负载
+    /// </summary>
+    public class RoundLoadBalancer : ILoadBalancer 
+    {
+        private ConcurrentDictionary<string, int> _serviceInvokeIndexs = new ConcurrentDictionary<string, int>();
+
+        /// <summary>
+        /// 轮询获取Endpoint
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <param name="endpoints"></param>
+        /// <returns></returns>
+        public string SelectEndpoint(string serviceName, List<string> endpoints)
+        {
+            endpoints = endpoints.OrderBy(q => q).ToList();
+            var index = _serviceInvokeIndexs.GetOrAdd(serviceName, 0);
+            if (index >= endpoints.Count)
+            {
+                index = _serviceInvokeIndexs.AddOrUpdate(serviceName, 0, (k, v) => 0);
+            }
+            _serviceInvokeIndexs.AddOrUpdate(serviceName, index, (k, v) => v + 1);
+            return endpoints.ElementAt(index);
+        }
+    }
+}

+ 46 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Model/ChannelConfig.cs

@@ -0,0 +1,46 @@
+using Grpc.Core;
+using System.Collections.Generic;
+
+namespace Grpc.Extension.Client.Model
+{
+    /// <summary>
+    /// ChannelConfig
+    /// </summary>
+    internal class ChannelConfig
+    {
+        /// <summary>
+        /// Discovery的服务器地址(http://192.168.8.6:8500)
+        /// </summary>
+        public string DiscoveryUrl { get; set; }
+
+        /// <summary>
+        /// Discovery上客户端服务名字
+        /// </summary>
+        public string DiscoveryServiceName { get; set; }
+
+        /// <summary>
+        /// 直接服务地址,不用服务现
+        /// </summary>
+        public string DirectEndpoint { get; set; }
+
+        /// <summary>
+        /// 是否使用直接服务地址
+        /// </summary>
+        public bool UseDirect { get; set; }
+
+        /// <summary>
+        /// Discovery上客户端服务Tag(可用于版本标记)
+        /// </summary>
+        public string DiscoveryServiceTag { get; set; }
+
+        /// <summary>
+        /// ChannelOption
+        /// </summary>
+        public IEnumerable<ChannelOption> ChannelOptions { get; set; }
+
+        /// <summary>
+        /// GrpcServiceName
+        /// </summary>
+        internal string GrpcServiceName { get; set; }
+    }
+}

+ 13 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Model/ChannelInfo.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Grpc.Core;
+
+namespace Grpc.Extension.Client.Model
+{
+    internal class ChannelInfo
+    {
+        public string DiscoveryServiceName { get; set; }
+        public Channel Channel { get; set; }
+    }
+}

+ 43 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Options/GrpcClientOptions.cs

@@ -0,0 +1,43 @@
+using Grpc.Extension.Abstract.Model;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Client
+{
+    /// <summary>
+    /// GrpcClientOptions
+    /// </summary>
+    public class GrpcClientOptions
+    {
+        /// <summary>
+        /// 服务发现地址(http://192.168.8.6:8500)
+        /// </summary>
+        public string DiscoveryUrl { get; set; }
+
+        /// <summary>
+        /// 服务地址缓存时间(秒)
+        /// </summary>
+        public int ServiceAddressCacheTime { get; set; } = 10;
+
+        /// <summary>
+        /// 默认错误码
+        /// </summary>
+        public int DefaultErrorCode
+        {
+            get { return GrpcErrorCode.DefaultErrorCode; }
+            set { GrpcErrorCode.DefaultErrorCode = value; }
+        }
+
+        /// <summary>
+        /// JaegerOptions
+        /// </summary>
+        public JaegerOptions Jaeger { get; set; }
+
+        /// <summary>
+        /// Grpc客户端调用超时时间(单位:秒)
+        /// </summary>
+        public double GrpcCallTimeOut { get; set; } = 10;
+    }
+
+}

+ 53 - 0
TEAMModelOS.SDK/Module/Grpc/Client/Options/JaegerOptions.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension
+{
+    /// <summary>
+    /// JaegerOptions
+    /// </summary>
+    public class JaegerOptions
+    {
+        /// <summary>
+        /// 是否启用Jaeger
+        /// </summary>
+        public bool Enable { get; set; } = true;
+
+        /// <summary>
+        /// 服务名
+        /// </summary>
+        public string ServiceName { get; set; }
+
+        /// <summary>
+        /// AgentIp
+        /// </summary>
+        public string AgentIp { get; set; }
+
+        /// <summary>
+        /// AgentPort
+        /// </summary>
+        public int AgentPort { get; set; }
+
+        /// <summary>
+        /// 检查参数配制
+        /// </summary>
+        /// <returns></returns>
+        public bool CheckConfig()
+        {
+            var key = "Jaeger";
+            if (this.Enable == false) return false;
+
+            if (string.IsNullOrWhiteSpace(this.ServiceName))
+                throw new ArgumentException($"{key}:ServiceName Value cannot be null");
+
+            if (string.IsNullOrWhiteSpace(this.AgentIp))
+                throw new ArgumentException($"{key}:AgentIp Value cannot be null");
+
+            if (this.AgentPort == 0)
+                throw new ArgumentNullException($"{key}:AgentPort Value cannot be null");
+
+            return true;
+        }
+    }
+}

+ 187 - 0
TEAMModelOS.SDK/Module/Grpc/Client/ServiceCollectionExtensions.cs

@@ -0,0 +1,187 @@
+using Grpc.Core;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Abstract.Discovery;
+using Grpc.Extension.Client.Interceptors;
+using Grpc.Extension.Client.Internal;
+using Grpc.Extension.Client.LoadBalancer;
+using Grpc.Extension.Client.Model;
+using Grpc.Extension.Common;
+using Grpc.Extension.Discovery;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using OpenTracing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace Grpc.Extension.Client
+{
+    /// <summary>
+    /// ServiceCollectionExtensions
+    /// </summary>
+    public static class ServiceCollectionExtensions
+    {
+        /// <summary>
+        /// 添加GrpcClient扩展
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="conf"></param>
+        /// <returns></returns>
+        public static IServiceCollection AddGrpcClientExtensions(this IServiceCollection services, IConfiguration conf)
+        {
+            //注入配制
+            services.Configure<GrpcClientOptions>(conf.GetSection("GrpcClient"));
+            //GrpcClientApp
+            services.AddSingleton<GrpcClientApp>();
+            //添加客户端中间件的CallInvoker
+            services.AddSingleton<AutoChannelCallInvoker>();
+            services.AddSingleton<CallInvoker, InterceptorCallInvoker>();
+            //添加Channel的Manager
+            services.AddSingleton<ChannelPool>();
+            services.AddSingleton<GrpcClientManager>();
+
+            //默认使用轮询负载策略,在外面可以注入其它策略
+            if (!services.Any(p => p.ServiceType == typeof(ILoadBalancer)))
+            {
+                services.AddSingleton<ILoadBalancer, RoundLoadBalancer>();
+            }
+
+            //默认使用consul服务注册,服务发现,在外面可以注入其它策略
+            if (!services.Any(p => p.ServiceType == typeof(IServiceRegister)))
+            {
+                services.AddConsulDiscovery();
+            }
+
+            //添加缓存
+            services.AddMemoryCache();
+            //添加客户端中间件
+            services.AddClientCallTimeout();
+            services.AddClientMonitor();
+            //Jaeger
+            services.AddClientJaeger(conf);
+
+            return services;
+        }
+
+        /// <summary>
+        /// 添加GrpcClient到Discovery,生成元数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="services"></param>
+        /// <param name="discoveryServiceName">Discovery上客户端服务名字</param>
+        /// <param name="discoveryUrl">Discovery的服务器地址</param>
+        /// <param name="channelOptions">ChannelOption</param>
+        /// <returns></returns>
+        public static IServiceCollection AddGrpcClient<T>(this IServiceCollection services, string discoveryServiceName, string discoveryUrl = "", IEnumerable<ChannelOption> channelOptions = null) where T : ClientBase<T>
+        {
+            services.AddSingleton<T>();
+            var channelConfig = new ChannelConfig
+            {
+                DiscoveryUrl = discoveryUrl,
+                DiscoveryServiceName = discoveryServiceName,
+                ChannelOptions = channelOptions
+            };
+            var bindFlags = BindingFlags.Static | BindingFlags.NonPublic;
+            channelConfig.GrpcServiceName = typeof(T).DeclaringType.GetFieldValue<string>("__ServiceName", bindFlags);
+            ChannelPool.Configs.Add(channelConfig);
+            return services;
+        }
+
+        /// <summary>
+        /// 添加GrpcClient到Discovery,生成元数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="services"></param>
+        /// <param name="discoveryServiceName">Discovery上客户端服务名字</param>
+        /// <param name="discoveryUrl">Discovery的服务器地址</param>
+        /// <param name="channelOptions">ChannelOption</param>
+        /// <returns></returns>
+        public static IServiceCollection AddGrpcClientByDiscovery<T>(this IServiceCollection services, string discoveryServiceName, string discoveryUrl = "", IEnumerable<ChannelOption> channelOptions = null) where T : ClientBase<T>
+        {
+            services.AddGrpcClient<T>(discoveryServiceName, discoveryUrl, channelOptions);
+
+            return services;
+        }
+
+        /// <summary>
+        /// 添加客户端日志监控Interceptor
+        /// </summary>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        private static IServiceCollection AddClientMonitor(this IServiceCollection services)
+        {
+            services.AddClientInterceptor<ClientMonitorInterceptor>();
+
+            return services;
+        }
+
+        /// <summary>
+        /// 添加客户端超时Interceptor
+        /// </summary>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        private static IServiceCollection AddClientCallTimeout(this IServiceCollection services)
+        {
+            services.AddSingleton<ClientInterceptor>(sp => 
+            {
+                var options = sp.GetService<IOptions<GrpcClientOptions>>().Value;
+                return new ClientCallTimeout(options.GrpcCallTimeOut);
+            });
+            return services;
+        }
+
+        /// <summary>
+        /// 添加Jaeger
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="conf"></param>
+        /// <returns></returns>
+        public static IServiceCollection AddClientJaeger(this IServiceCollection services, IConfiguration conf)
+        {
+            //读取Jaeger配制
+            var key = conf["GrpcServer:ServiceAddress"] != null ? "GrpcServer" : "GrpcClient";
+            var jaegerOptions = conf.GetSection($"{key}:Jaeger").Get<JaegerOptions>();
+            if (jaegerOptions == null || jaegerOptions.Enable == false)
+                return services;
+
+            //jaeger
+            if (!services.Any(p => p.ServiceType == typeof(ITracer)))
+            {
+                services.AddSingleton<ITracer>(sp =>
+                {
+                    var options = sp.GetService<IOptions<GrpcClientOptions>>().Value;
+                    var tracer = new Jaeger.Tracer.Builder(options.Jaeger.ServiceName)
+                    .WithLoggerFactory(sp.GetService<ILoggerFactory>())
+                    .WithSampler(new Jaeger.Samplers.ConstSampler(true))
+                    .WithReporter(new Jaeger.Reporters.RemoteReporter.Builder()
+                        .WithFlushInterval(TimeSpan.FromSeconds(5))
+                        .WithMaxQueueSize(5)
+                        .WithSender(new Jaeger.Senders.UdpSender(jaegerOptions.AgentIp, jaegerOptions.AgentPort, 1024 * 5)).Build())
+                    .Build();
+                    return tracer;
+                });
+            }                
+            //添加jaeger中间件
+            services.AddClientInterceptor<ClientJaegerTracingInterceptor>();
+
+            return services;
+        } 
+
+        /// <summary>
+        /// 添加客户端Interceptor
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        public static IServiceCollection AddClientInterceptor<T>(this IServiceCollection services) where T : ClientInterceptor
+        {
+            services.AddSingleton<ClientInterceptor, T>();
+
+            return services;
+        }
+    }
+}

+ 50 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/CmdService.cs

@@ -0,0 +1,50 @@
+using Grpc.Core;
+using System;
+using System.Threading.Tasks;
+using Grpc.Extension.BaseService.Model;
+
+namespace Grpc.Extension.BaseService
+{
+    /// <summary>
+    /// 执行命令的服务
+    /// </summary>
+    public class CmdService : IGrpcBaseService
+    {
+        /// <summary>
+        /// 添加删除截流的method
+        /// </summary>
+        public Task<CmdRS> AddDelThrottle(AddDelThrottleRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                if (string.IsNullOrWhiteSpace(rq.MethodName))
+                {
+                    return CmdRS.Fail("MethodName is null");
+                }
+                if(rq.IsDel)
+                    ThrottleManager.Instance.Del(rq.MethodName);
+                else
+                    ThrottleManager.Instance.Add(rq.MethodName);
+                return CmdRS.Success();
+            });
+        }
+        /// <summary>
+        /// 添加删除是否允许保存响应的method
+        /// </summary>
+        public Task<CmdRS> AddDelSaveResponseEnable(AddDelSaveResponseEnableRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                if (string.IsNullOrWhiteSpace(rq.MethodName))
+                {
+                    return CmdRS.Fail("MethodName is null");
+                }
+                if (rq.IsDel)
+                    MonitorManager.Instance.DelSaveResponseMethod(rq.MethodName);
+                else
+                    MonitorManager.Instance.AddSaveResponseMethod(rq.MethodName);
+                return CmdRS.Success();
+            });
+        }
+    }
+}

+ 15 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/IGrpcBaseService.cs

@@ -0,0 +1,15 @@
+using Grpc.Extension.Abstract;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.BaseService
+{
+    /// <summary>
+    /// 基础服务
+    /// </summary>
+    public interface IGrpcBaseService : IGrpcService
+    {
+
+    }
+}

+ 83 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MetaService.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Extension.BaseService.Model;
+using System.Linq;
+using Grpc.Extension.Common;
+
+namespace Grpc.Extension.BaseService
+{
+    /// <summary>
+    /// Grpc元数据服务
+    /// </summary>
+    public class MetaService : IGrpcBaseService
+    {
+        /// <summary>
+        /// 服务基本信息
+        /// </summary>
+        public Task<InfoRS> Info(InfoRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methods = MetaModel.Methods.Select(q => q.FullName?.Trim()).ToList();
+                if (!string.IsNullOrWhiteSpace(rq.MethodName))
+                {
+                    methods = methods?.Where(q => q.ToLower().Contains(rq.MethodName.Trim().ToLower())).ToList();
+                }
+                var methodInfos = new List<GrpcMethodInfo>();
+                foreach (var m in methods)
+                {
+                    var info = new GrpcMethodInfo { Name = m };
+                    info.IsThrottled = ThrottleManager.Instance.IsThrottled(m);
+                    info.SaveResponseEnable = MonitorManager.Instance.SaveResponseMethodEnable(m);
+                    methodInfos.Add(info);
+                }
+                return new InfoRS
+                {
+                    IpAndPort = $"{MetaModel.Ip}:{MetaModel.Port}",
+                    StartTime = MetaModel.StartTime.ToUnixTimestamp(),
+                    MethodInfos = methodInfos
+                };
+            });
+        }
+        /// <summary>
+        /// 服务方法的详细信息
+        /// </summary>
+        public Task<MethodInfoRS> MethodInfo(MethodInfoRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methodInfo = MetaModel.Methods.FirstOrDefault(q => q.FullName == rq.FullName?.Trim());
+                if (methodInfo == null)
+                {
+                    return new MethodInfoRS();
+                }
+                return new MethodInfoRS
+                {
+                    RequestJson = Activator.CreateInstance(methodInfo.RequestType).FillProp().ToJson(ignoreNullValue: false, isIndented: true),
+                    ResponseJson = Activator.CreateInstance(methodInfo.ResponseType).FillProp().ToJson(ignoreNullValue: false, isIndented: true)
+                };
+            });
+        }
+        /// <summary>
+        /// 服务方法调用
+        /// </summary>
+        public Task<MethodInvokeRS> MethodInvoke(MethodInvokeRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methodInfo = MetaModel.Methods.FirstOrDefault(q => q.FullName == rq.FullName?.Trim());
+                if (methodInfo == null)
+                {
+                    return new MethodInvokeRS() { ResponseJson = $"not fount method by fullname:{rq.FullName}" };
+                }
+                var task = (Task)methodInfo.Handler.DynamicInvoke(rq.RequestJson?.Trim().FromJson(methodInfo.RequestType), context);
+                task.Wait();
+                dynamic result = task;
+                return new MethodInvokeRS { ResponseJson = ((object)result.Result).ToJson(ignoreNullValue: false, isIndented: true) };
+            });
+        }
+    }
+}

+ 91 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MetaServiceAspnetCore.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Extension.BaseService.Model;
+using System.Linq;
+using Grpc.Extension.Common;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Grpc.Extension.BaseService
+{
+    /// <summary>
+    /// Grpc元数据服务
+    /// </summary>
+    public class MetaServiceAspnetCore : IGrpcBaseService
+    {
+        private readonly IServiceProvider _serviceProvider;
+
+        public MetaServiceAspnetCore(IServiceProvider serviceProvider)
+        {
+            _serviceProvider = serviceProvider;
+        }
+        /// <summary>
+        /// 服务基本信息
+        /// </summary>
+        public Task<InfoRS> Info(InfoRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methods = MetaModel.Methods.Select(q => q.FullName?.Trim()).ToList();
+                if (!string.IsNullOrWhiteSpace(rq.MethodName))
+                {
+                    methods = methods?.Where(q => q.ToLower().Contains(rq.MethodName.Trim().ToLower())).ToList();
+                }
+                var methodInfos = new List<GrpcMethodInfo>();
+                foreach (var m in methods)
+                {
+                    var info = new GrpcMethodInfo { Name = m };
+                    info.IsThrottled = ThrottleManager.Instance.IsThrottled(m);
+                    info.SaveResponseEnable = MonitorManager.Instance.SaveResponseMethodEnable(m);
+                    methodInfos.Add(info);
+                }
+                return new InfoRS
+                {
+                    IpAndPort = $"{MetaModel.Ip}:{MetaModel.Port}",
+                    StartTime = MetaModel.StartTime.ToUnixTimestamp(),
+                    MethodInfos = methodInfos
+                };
+            });
+        }
+        /// <summary>
+        /// 服务方法的详细信息
+        /// </summary>
+        public Task<MethodInfoRS> MethodInfo(MethodInfoRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methodInfo = MetaModel.Methods.FirstOrDefault(q => q.FullName == rq.FullName?.Trim());
+                if (methodInfo == null)
+                {
+                    return new MethodInfoRS();
+                }
+                return new MethodInfoRS
+                {
+                    RequestJson = Activator.CreateInstance(methodInfo.RequestType).FillProp().ToJson(ignoreNullValue: false, isIndented: true),
+                    ResponseJson = Activator.CreateInstance(methodInfo.ResponseType).FillProp().ToJson(ignoreNullValue: false, isIndented: true)
+                };
+            });
+        }
+        /// <summary>
+        /// 服务方法调用
+        /// </summary>
+        public Task<MethodInvokeRS> MethodInvoke(MethodInvokeRQ rq, ServerCallContext context)
+        {
+            return Task.Run(() =>
+            {
+                var methodInfo = MetaModel.Methods.FirstOrDefault(q => q.FullName == rq.FullName?.Trim());
+                if (methodInfo == null)
+                {
+                    return new MethodInvokeRS() { ResponseJson = $"not fount method by fullname:{rq.FullName}" };
+                }
+                var service = ActivatorUtilities.CreateInstance(_serviceProvider, methodInfo.ServiceType);
+                var task = (Task)methodInfo.Handler.DynamicInvoke(service, rq.RequestJson?.Trim().FromJson(methodInfo.RequestType), context);
+                task.Wait();
+                dynamic result = task;
+                return new MethodInvokeRS { ResponseJson = ((object)result.Result).ToJson(ignoreNullValue: false, isIndented: true) };
+            });
+        }
+    }
+}

+ 14 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/AddDelSaveResponseEnableRQ.cs

@@ -0,0 +1,14 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class AddDelSaveResponseEnableRQ
+    {
+        [ProtoMember(1)]
+        public string MethodName { get; set; }
+
+        [ProtoMember(2)]
+        public bool IsDel { get; set; }
+    }
+}

+ 14 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/AddDelThrottleRQ.cs

@@ -0,0 +1,14 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class AddDelThrottleRQ
+    {
+        [ProtoMember(1)]
+        public string MethodName { get; set; }
+
+        [ProtoMember(2)]
+        public bool IsDel { get; set; }
+    }
+}

+ 24 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Cmd/CmdRS.cs

@@ -0,0 +1,24 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class CmdRS
+    {
+        [ProtoMember(1)]
+        public bool Result { get; set; }
+
+        [ProtoMember(2)]
+        public string Message { get; set; }
+
+        public static CmdRS Success(string msg = null)
+        {
+            return new CmdRS { Result = true, Message = msg };
+        }
+
+        public static CmdRS Fail(string msg)
+        {
+            return new CmdRS { Result = false, Message = msg };
+        }
+    }
+}

+ 12 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/InfoRQ.cs

@@ -0,0 +1,12 @@
+
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class InfoRQ
+    {
+        [ProtoMember(1)]
+        public string MethodName { get; set; }
+    }
+}

+ 28 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/InfoRS.cs

@@ -0,0 +1,28 @@
+using ProtoBuf;
+using System.Collections.Generic;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class InfoRS
+    {
+        [ProtoMember(1)]
+        public string IpAndPort { get; set; }
+
+        [ProtoMember(2)]
+        public long StartTime { get; set; }
+
+        [ProtoMember(3)]
+        public List<GrpcMethodInfo> MethodInfos { get; set; }
+    }
+
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class GrpcMethodInfo
+    {
+        public string Name { get; set; }
+
+        public bool SaveResponseEnable { get; set; }
+
+        public bool IsThrottled { get; set; }
+    }
+}

+ 30 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MetaModel.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    public class MetaModel
+    {
+        public static string Ip { get; set; }
+
+        public static int Port { get; set; }
+
+        public static DateTime StartTime { get; set; }
+
+        public static List<MetaMethodModel> Methods { get; set; } = new List<MetaMethodModel>();
+    }
+
+    public class MetaMethodModel
+    {
+        public string FullName { get; set; }
+
+        public Type RequestType { get; set; }
+
+        public Type ResponseType { get; set; }
+
+        public Delegate Handler { get; set; }
+
+        public Type ServiceType { get; set; }
+    }
+}

+ 11 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInfoRQ.cs

@@ -0,0 +1,11 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class MethodInfoRQ
+    {
+        [ProtoMember(1)]
+        public string FullName { get; set; }
+    }
+}

+ 14 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInfoRS.cs

@@ -0,0 +1,14 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class MethodInfoRS
+    {
+        [ProtoMember(1)]
+        public string RequestJson { get; set; }
+
+        [ProtoMember(2)]
+        public string ResponseJson { get; set; }
+    }
+}

+ 23 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInvokeRQ.cs

@@ -0,0 +1,23 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    /// <summary>
+    /// MethodInvokeRQ
+    /// </summary>
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class MethodInvokeRQ
+    {
+        /// <summary>
+        /// GrpcMethod FullName
+        /// </summary>
+        [ProtoMember(1)]
+        public string FullName { get; set; }
+
+        /// <summary>
+        /// RequestJson
+        /// </summary>
+        [ProtoMember(2)]
+        public string RequestJson { get; set; }
+    }
+}

+ 10 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/Meta/MethodInvokeRS.cs

@@ -0,0 +1,10 @@
+using ProtoBuf;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
+    public class MethodInvokeRS
+    {
+        public string ResponseJson { get; set; }
+    }
+}

+ 38 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/ProtoInfo.cs

@@ -0,0 +1,38 @@
+using Grpc.Core;
+using ProtoBuf;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    public class ProtoInfo
+    {
+        /// <summary>
+        /// grpc服务方法信息 用于生成proto文件
+        /// </summary>
+        public static List<ProtoMethodInfo> Methods { get; internal set; } = new List<ProtoMethodInfo>();
+    }
+
+    /// <summary>
+    /// 注册到grpc的服务方法信息
+    /// </summary>
+    public class ProtoMethodInfo
+    {
+        public string ServiceName { get; set; }
+
+        public string MethodName { get; set; }
+
+        public string RequestName { get; set; }
+
+        public string ResponseName { get; set; }
+
+        public string FullName
+        {
+            get { return "/" + ServiceName + "/" + MethodName; }
+        }
+
+        public MethodType MethodType { get; set; }
+
+        public static ConcurrentDictionary<string, string> Protos = new ConcurrentDictionary<string, string>();
+    }
+}

+ 13 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/ServerConsts.cs

@@ -0,0 +1,13 @@
+namespace Grpc.Extension.BaseService.Model
+{
+    public class ServerConsts
+    {
+        public const string BaseServicePackage = "grpc";
+
+        public const string BaseServiceName = "BaseService";
+
+        public const string NotResponseMsg = "not enable save response";
+
+        public const string ThrottledMsg = "this request is throttled";
+    }
+}

+ 24 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/Model/XmlCommentInfo.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.BaseService.Model
+{
+    internal class XmlCommentInfo
+    {
+        /// <summary>
+        /// FullName(Math.MathGrpc.Add(Math.Model.AddRequest,Grpc.Core.ServerCallContext))
+        /// </summary>
+        public string FullName { get; set; }
+
+        /// <summary>
+        /// Type(T:类,M:方法,P:属性,F:字段,E:事件)
+        /// </summary>
+        public string Type { get; set; }
+
+        /// <summary>
+        /// Summary(注释)
+        /// </summary>
+        public string Summary { get; set; }
+    }
+}

+ 44 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/MonitorManager.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Grpc.Extension.BaseService
+{
+    public class MonitorManager
+    {
+        private static readonly object syncSaveResponseMethods = new object();
+        private static List<string> saveResponseMethods = new List<string>();
+        private static readonly Lazy<MonitorManager> instance = new Lazy<MonitorManager>(() => new MonitorManager(), true);
+
+        public static MonitorManager Instance
+        {
+            get { return instance.Value; }
+        }
+
+        #region 是否记录响应数据到日志
+        public void AddSaveResponseMethod(string fullName)
+        {
+            if (string.IsNullOrWhiteSpace(fullName)) return;
+            lock (syncSaveResponseMethods)
+            {
+                saveResponseMethods.Add(fullName);
+                saveResponseMethods = saveResponseMethods.Distinct().ToList();
+            }
+        }
+
+        public void DelSaveResponseMethod(string fullName)
+        {
+            if (string.IsNullOrWhiteSpace(fullName)) return;
+            lock (syncSaveResponseMethods)
+            {
+                saveResponseMethods.Remove(fullName);
+            }
+        }
+
+        public bool SaveResponseMethodEnable(string fullName)
+        {
+            return GrpcExtensionsOptions.Instance.GlobalSaveResponseEnable || (!string.IsNullOrWhiteSpace(fullName) && saveResponseMethods.Contains(fullName));
+        }
+        #endregion
+    }
+}

+ 42 - 0
TEAMModelOS.SDK/Module/Grpc/Common/BaseService/ThrottleManager.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Grpc.Extension.BaseService
+{
+    public class ThrottleManager
+    {
+        private static readonly object sync = new object();
+        private List<string> throttleMethods = new List<string>();
+        private static Lazy<ThrottleManager> instance = new Lazy<ThrottleManager>(() => new ThrottleManager(), true);
+        public static ThrottleManager Instance => instance.Value;
+
+        public void Add(string fullName)
+        {
+            if (string.IsNullOrWhiteSpace(fullName)) return;
+            lock (sync)
+            {
+                throttleMethods.Add(fullName.Trim());
+                throttleMethods = throttleMethods.Distinct().ToList();
+            }
+        }
+
+        public void Del(string fullName)
+        {
+            if (string.IsNullOrWhiteSpace(fullName)) return;
+            lock (sync)
+            {
+                throttleMethods.Remove(fullName.Trim());
+            }
+        }
+
+        public bool IsThrottled(string fullName)
+        {
+            if (string.IsNullOrWhiteSpace(fullName)) return false;
+            lock (sync)
+            {
+                return throttleMethods.Contains(fullName.Trim());
+            }
+        }
+    }
+}

+ 52 - 0
TEAMModelOS.SDK/Module/Grpc/Common/CommonError.cs

@@ -0,0 +1,52 @@
+using Grpc.Core;
+using System;
+using Grpc.Extension.Abstract.Model;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// 统一错误构建
+    /// </summary>
+    public class CommonError
+    {
+        /// <summary>
+        /// 返回一个rpc异常到客户端
+        /// </summary>
+        public static RpcException BuildRpcException(Exception ex)
+        {
+            if (ex is RpcException)
+            {
+                return ex as RpcException;
+            }
+            else if (ex.InnerException is RpcException)
+            {
+                return ex.InnerException as RpcException;
+            }
+            //构建RpcException
+            var errModel = new ErrorModel
+            {
+                Code = ParseCode(ex),
+                Detail = ex.Message,
+                Internal = ex.GetFlatException(),
+                Status = (int)StatusCode.Internal
+            };
+            var rpcEx = new RpcException(new Status(StatusCode.Internal, errModel.ToJson()));
+            rpcEx.Data.Add("ErrorCode", errModel.Code);
+            return rpcEx;
+        }
+
+        private static int ParseCode(Exception ex)
+        {
+            try
+            {
+                dynamic d = ex.InnerException == null ? ex : ex.InnerException;
+                var code = d.Code;
+                return code;
+            }
+            catch
+            {
+                return GrpcErrorCode.DefaultErrorCode + GrpcErrorCode.Internal;
+            }
+        }
+    }
+}

+ 34 - 0
TEAMModelOS.SDK/Module/Grpc/Common/DateTimeExtensions.cs

@@ -0,0 +1,34 @@
+using System;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// DateTimeExtensions
+    /// </summary>
+    public static class DateTimeExtensions
+    {
+        /// <summary>
+        /// unixtime to datetime
+        /// </summary>
+        /// <param name="unixtime"></param>
+        /// <returns></returns>
+        public static DateTime FromUnixTimestamp(this long unixtime)
+        {
+            //DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            DateTime sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local);
+            return sTime.AddMilliseconds(unixtime);
+        }
+
+        /// <summary>
+        /// datetime to unixtime
+        /// </summary>
+        /// <param name="datetime"></param>
+        /// <returns></returns>
+        public static long ToUnixTimestamp(this DateTime datetime)
+        {
+            //DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            DateTime sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local);
+            return (long)(datetime - sTime).TotalMilliseconds;
+        }
+    }
+}

+ 31 - 0
TEAMModelOS.SDK/Module/Grpc/Common/ExceptionExtensions.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Common
+{
+    public static class ExceptionExtensions
+    {
+        /// <summary>
+        /// 返回一个FlatException
+        /// </summary>
+        /// <param name="ex"></param>
+        /// <returns></returns>
+        public static string GetFlatException(this Exception ex)
+        {
+            var exception = "";
+            if (ex is AggregateException aex)
+            {
+                foreach (var e in aex.Flatten().InnerExceptions)
+                {
+                    exception += e?.ToString() + Environment.NewLine;
+                }
+            }
+            else
+            {
+                exception = ex.ToString();
+            }
+            return exception;
+        }
+    }
+}

+ 31 - 0
TEAMModelOS.SDK/Module/Grpc/Common/HostBuilderExtensions.cs

@@ -0,0 +1,31 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Grpc.Extension.Common
+{
+    public static class HostBuilderExtensions
+    {
+        /// <summary>
+        /// UseStartup
+        /// </summary>
+        /// <typeparam name="TStartup"></typeparam>
+        /// <param name="hostBuilder"></param>
+        /// <returns></returns>
+        public static IHostBuilder UseStartup<TStartup>(this IHostBuilder hostBuilder) where TStartup : class
+        {
+            hostBuilder.ConfigureServices((ctx, services) => {
+                //build
+                services.AddSingleton<TStartup>();
+                var provider = services.BuildServiceProvider();
+                //get service
+                dynamic startup = provider.GetService<TStartup>();
+                //dynamic invoke
+                startup.ConfigureServices(services);
+            });
+            return hostBuilder;
+        }
+    }
+}

+ 179 - 0
TEAMModelOS.SDK/Module/Grpc/Common/Internal/ProtoCommentGenerator.cs

@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using System.Reflection;
+using ProtoBuf;
+using Grpc.Extension.BaseService.Model;
+
+namespace Grpc.Extension.Common.Internal
+{
+    internal static class ProtoCommentGenerator
+    {
+        //Xml文档注释
+        static List<XmlCommentInfo> xmlComments = new List<XmlCommentInfo>();
+        //ProtoType
+        static List<Type> protoTypes;
+        static ProtoCommentGenerator()
+        {
+            //加载注释xml文件
+            var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml");
+            var assembliyNames = new List<string>();
+            foreach (var file in files)
+            {
+                var xe = XElement.Load(file);
+                //检查是否为注释xml文件
+                if (xe.Element("assembly") == null || xe.Element("members") == null) continue;
+                assembliyNames.Add(xe.Element("assembly").Value);
+                foreach (var item in xe.Element("members").Elements())
+                {
+                    var name = item.Attribute("name")?.Value;
+                    var nameArr = name?.Split(':');
+                    if (name != null && nameArr.Length > 1)
+                    {
+                        xmlComments.Add(new XmlCommentInfo()
+                        {
+                            FullName = nameArr[1],
+                            Type = nameArr[0],
+                            Summary = item.Element("summary")?.Value?.Trim()
+                        });
+                    }
+                }
+            }
+
+            //初始化protoTypes
+            var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(p => assembliyNames.Contains(p.GetName().Name));
+            protoTypes = assemblies.SelectMany(p => p.GetTypes().Where(t => t.GetCustomAttribute<ProtoContractAttribute>() != null)).ToList();
+        }
+
+        /// <summary>
+        /// 获取注释集合
+        /// </summary>
+        /// <param name="types"></param>
+        /// <param name="fullName"></param>
+        /// <returns></returns>
+        public static Dictionary<string,string> GetComments(string[] types,string fullName)
+        {
+            return xmlComments.Where(p => types.Contains(p.Type) && p.FullName.StartsWith(fullName)).ToDictionary(p => p.FullName, p => p.Summary);
+        }
+
+        /// <summary>
+        /// 获取注释
+        /// </summary>
+        /// <param name="type"></param>
+        /// <param name="fullName"></param>
+        /// <returns></returns>
+        public static string GetComment(string type, string fullName)
+        {
+            return xmlComments.FirstOrDefault(p => p.Type == type && p.FullName.StartsWith(fullName))?.Summary;
+        }
+
+        /// <summary>
+        /// 给Message加入注释
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <param name="proto"></param>
+        /// <returns></returns>
+        public static string AddMessageComment<TEntity>(this string proto)
+        {
+            var dicComment = new Dictionary<string,string>();
+
+            var lines = new List<string>();
+            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(proto)))
+            using (var sr = new StreamReader(ms))
+            {
+                while (sr.Peek() > 0)
+                {
+                    var line = sr.ReadLine();
+                    var lineArr = line.Split(new string[]{ " ", "repeated" },StringSplitOptions.RemoveEmptyEntries);
+                    if (lineArr.Length > 1)
+                    {
+                        var typeName = lineArr[1];//message和enum后的类型名
+                        if (ProtoGenerator.protoMsgStartWithKeywords.Any(q => line.StartsWith(q)))
+                        {
+                            var fullName = GetProtoTypeFullName<TEntity>(typeName);
+                            if(!string.IsNullOrEmpty(fullName)) dicComment = GetComments(new string[] { "T", "P","F" }, fullName);
+                        }
+                        var propertyName = lineArr[1];//属性名
+                        var comment = dicComment.FirstOrDefault(p => p.Key.EndsWith("." + propertyName)).Value;
+                        if (!string.IsNullOrWhiteSpace(comment))
+                        {
+                            if (line.EndsWith(";"))
+                            {
+                                lines.Add(AddComment(comment, "   "));
+                            }
+                            else
+                            {
+                                lines.Add(AddComment(comment));
+                            }
+                            
+                        }
+                    }
+                    lines.Add(line);
+                }
+            }
+
+            return string.Join(Environment.NewLine, lines);
+        }
+
+        //添加注释(多行注释)
+        private static string AddComment(string comment, string prefix = "")
+        {
+            var arr = comment.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+            return string.Join(Environment.NewLine, arr.Select(p => $"{prefix}//{p.TrimStart()}"));
+        }
+
+        /// <summary>
+        /// 根据名字获取ProtoType的FullName
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <param name="name"></param>
+        /// <returns></returns>
+        private static string GetProtoTypeFullName<TEntity>(string name)
+        {
+            //判断TEntity是否就是要获取的类型
+            if (typeof(TEntity).Name == name) return typeof(TEntity).FullName;
+            //从protoTypes里获取
+            var type = protoTypes.Where(t => t.Name == name).FirstOrDefault();
+            return type?.FullName;
+        }
+
+        /// <summary>
+        /// 给Service加入注释
+        /// </summary>
+        /// <param name="proto"></param>
+        /// <param name="sb"></param>
+        public static void AddServiceComment(ProtoMethodInfo proto,StringBuilder sb)
+        {
+            var comment = string.Empty;
+            var handler = MetaModel.Methods.FirstOrDefault(p => p.FullName == proto.FullName)?.Handler;
+            if (handler != null)
+            {
+
+                //var fullName = handler.Method.GetPropertyValue<string>("FullName", BindingFlags.Instance | BindingFlags.NonPublic);
+                var fullName = GetMethodFullName(handler.Method);
+                //将方法的FullName转换成注释的FullName
+                var xmlFullName = fullName.Replace(" ", "").Replace("`1[", "{").Replace("]", "}");
+                comment = GetComment("M", xmlFullName);
+                if (!string.IsNullOrWhiteSpace(comment))
+                {
+                    sb.AppendLine(AddComment(comment, "   "));
+                }
+            }
+        }
+
+        /// <summary>
+        /// 获取方法的FullName
+        /// </summary>
+        /// <param name="method"></param>
+        /// <returns></returns>
+        private static string GetMethodFullName(MethodInfo method)
+        {
+            var parameters = method.GetParameters();
+            var paraStr = string.Join(",", parameters.Select(p => p.ParameterType.ToString()));
+            return $"{method.DeclaringType.FullName}.{method.Name}({paraStr})";
+        }
+    }
+}

+ 231 - 0
TEAMModelOS.SDK/Module/Grpc/Common/Internal/ProtoGenerator.cs

@@ -0,0 +1,231 @@
+using Grpc.Extension.BaseService.Model;
+using ProtoBuf;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Grpc.Extension.Common.Internal
+{
+    public static class ProtoGenerator
+    {
+        /// <summary>
+        /// proto的message可能的开头的关键字
+        /// </summary>
+        internal static List<string> protoMsgStartWithKeywords { get; set; } = new List<string> { "message", "enum" };
+
+        /// <summary>
+        /// 添加proto
+        /// </summary>
+        public static void AddProto<TEntity>(string entityName)
+        {
+            if (!ProtoMethodInfo.Protos.ContainsKey(entityName))
+            {
+                var msg = Serializer.GetProto<TEntity>(ProtoBuf.Meta.ProtoSyntax.Proto3);
+                ProtoMethodInfo.Protos.TryAdd(entityName, msg.FilterHead().AddMessageComment<TEntity>());
+            }
+        }
+        /// <summary>
+        /// 获取实体对应的proto
+        /// </summary>
+        internal static string GetProto(string entityName)
+        {
+            var rst = ProtoMethodInfo.Protos.TryGetValue(entityName, out string proto);
+            return rst ? proto : null;
+        }
+
+        /// <summary>
+        /// 过滤头部 只保留message部分
+        /// </summary>
+        internal static string FilterHead(this string proto)
+        {
+            var lines = new List<string>();
+            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(proto)))
+            using (var sr = new StreamReader(ms))
+            {
+                var readEnable = false;
+                while (sr.Peek() > 0)
+                {
+                    var line = sr.ReadLine();
+                    if (protoMsgStartWithKeywords.Any(q => line.StartsWith(q)))
+                    {
+                        readEnable = true;
+                    }
+                    if (readEnable)
+                    {
+                        lines.Add(line);
+                    }
+                }
+            }
+            return string.Join(Environment.NewLine, lines);
+        }
+        /// <summary>
+        /// 生成grpc的message的proto内容
+        /// </summary>
+        private static string GenGrpcMessageProto(string pkgName,string srvName, List<string> msgProtos, bool spiltProto)
+        {
+            var sb = new StringBuilder();
+            if (spiltProto)
+            {
+                sb.AppendLine("syntax = \"proto3\";");
+                if (!string.IsNullOrWhiteSpace(GrpcExtensionsOptions.Instance.ProtoNameSpace))
+                {
+                    sb.AppendLine("option csharp_namespace = \"" + GrpcExtensionsOptions.Instance.ProtoNameSpace.Trim() + "." + srvName + "\";");
+                }
+                if (!string.IsNullOrWhiteSpace(pkgName))
+                {
+                    sb.AppendLine($"package {pkgName.Trim() + "." + srvName};");
+                }
+            }
+            sb.AppendLine();
+            sb.AppendLine(Environment.NewLine);
+
+            //过滤重复的message
+            var sbMsg = new StringBuilder();
+            foreach (var proto in msgProtos)
+            {
+                sbMsg.AppendLine(proto);
+            }
+            var msg = sbMsg.ToString();
+            var msgMapProtos = new Dictionary<string, List<string>>();
+            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(msg)))
+            using (var sr = new StreamReader(ms))
+            {
+                var msgName = "";
+                var lines = new List<string>();
+                while (sr.Peek() > 0)
+                {
+                    var line = sr.ReadLine();
+                    if (protoMsgStartWithKeywords.Any(q => line.StartsWith(q)))
+                    {
+                        msgName = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries)[1];
+                    }
+
+                    lines.Add(line);
+
+                    if (line.StartsWith("}"))
+                    {
+                        if (!msgMapProtos.ContainsKey(msgName))
+                        {
+                            msgMapProtos.Add(msgName, lines.Select(q => q).ToList());
+                        }
+                        lines.Clear();
+                    }
+                }
+            }
+            msg = string.Join(Environment.NewLine + Environment.NewLine, msgMapProtos.Select(q => string.Join(Environment.NewLine, q.Value)));
+            sb.Append(msg);
+            return sb.ToString();
+        }
+        /// <summary>
+        /// 生成grpc的service的proto内容
+        /// </summary>
+        private static string GenGrpcServiceProto(string msgProtoName, string pkgName, string srvName, List<ProtoMethodInfo> methodInfo, bool spiltProto)
+        {
+            var sb = new StringBuilder();
+            sb.AppendLine("syntax = \"proto3\";");
+            if (!string.IsNullOrWhiteSpace(GrpcExtensionsOptions.Instance.ProtoNameSpace))
+            {
+                sb.AppendLine("option csharp_namespace = \"" + GrpcExtensionsOptions.Instance.ProtoNameSpace.Trim() +"."+ srvName + "\";");
+            }
+            if (!string.IsNullOrWhiteSpace(pkgName))
+            {
+                sb.AppendLine($"package {pkgName.Trim()+"."+ srvName};");
+            }
+            if (spiltProto)
+            {
+                sb.AppendLine(string.Format("import \"{0}\";", msgProtoName));
+            }
+            sb.AppendLine(Environment.NewLine);
+            sb.AppendLine("service " + srvName + " {");
+
+            var template = @"   rpc {0}({1}) returns({2})";
+            methodInfo.ForEach(q => {
+                var requestName = q.RequestName;
+                var responseName = q.ResponseName;
+                switch (q.MethodType)
+                {
+                    case Core.MethodType.Unary:
+                        break;
+                    case Core.MethodType.ClientStreaming:
+                        requestName = "stream " + requestName;
+                        break;
+                    case Core.MethodType.ServerStreaming:
+                        responseName = "stream " + responseName;
+                        break;
+                    case Core.MethodType.DuplexStreaming:
+                        requestName = "stream " + requestName;
+                        responseName = "stream " + responseName;
+                        break;
+                }
+                ProtoCommentGenerator.AddServiceComment(q,sb);
+                sb.AppendLine(string.Format(template, q.MethodName, requestName, responseName) + ";" + Environment.NewLine);
+            });
+
+            sb.AppendLine("}");
+            return sb.ToString();
+        }
+        /// <summary>
+        /// 生成proto文件
+        /// </summary>
+        public static void Gen(string dir,bool spiltProto)
+        {
+            if (ProtoInfo.Methods == null || ProtoInfo.Methods.Count == 0) return;
+            if (!Directory.Exists(dir))
+            {
+                Directory.CreateDirectory(dir);
+            }
+
+            foreach (var grp in ProtoInfo.Methods.GroupBy(q => q.ServiceName))
+            {
+                var arr = grp.Key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
+                if (arr.Length > 2) continue;
+                var pkg = arr.Length == 2 ? arr[0] : null;
+                var srv = arr.Length == 2 ? arr[1] : arr[0];
+
+                #region message
+                var protoName = srv;//grp.Key;
+                var msgProtoName = $"{protoName}{(spiltProto ? ".message":"")}.proto";
+                var msgProtoPath = Path.Combine(dir, msgProtoName);
+                var msgProtos = new List<string>();
+                var rqNames = grp.ToList().Select(q => q.RequestName).ToList();
+                var rsNames = grp.ToList().Select(q => q.ResponseName).ToList();
+                var msgNames = rqNames.Union(rsNames).Distinct().ToList();
+                foreach (var n in msgNames)
+                {
+                    msgProtos.Add(GetProto(n));
+                }
+                var msgProtoContent = GenGrpcMessageProto(pkg ,srv, msgProtos, spiltProto);
+                #endregion
+
+                #region service
+                var srvProtoName = $"{protoName}{(spiltProto ? ".service":"")}.proto";
+                var srvProtoPath = Path.Combine(dir, srvProtoName);
+                var methodInfos = grp.ToList();
+                var srvProtoContent = GenGrpcServiceProto(msgProtoName, pkg, srv, methodInfos, spiltProto);
+                #endregion
+
+                //是否拆分message和service协议
+                if (spiltProto)
+                {
+                    //写message协议文件
+                    if (File.Exists(msgProtoPath)) File.Delete(msgProtoPath);
+                    File.AppendAllText(msgProtoPath, msgProtoContent);
+                    //写service协议文件
+                    if (File.Exists(srvProtoPath)) File.Delete(srvProtoPath);
+                    File.AppendAllText(srvProtoPath, srvProtoContent);
+
+                }
+                else
+                {
+                    var protoPath = Path.Combine(dir, $"{protoName}.proto");
+                    //写协议文件
+                    if (File.Exists(protoPath)) File.Delete(protoPath);
+                    File.AppendAllText(protoPath, srvProtoContent);
+                    File.AppendAllText(protoPath, msgProtoContent);
+                }
+            }
+        }
+    }
+}

+ 18 - 0
TEAMModelOS.SDK/Module/Grpc/Common/Internal/ServerCallContextAccessor.cs

@@ -0,0 +1,18 @@
+using Grpc.Core;
+using System.Threading;
+
+namespace Grpc.Extension.Common.Internal
+{
+    /// <summary>
+    /// ServerCallContextAccessor
+    /// </summary>
+    public static class ServerCallContextAccessor
+    {
+        private static readonly AsyncLocal<ServerCallContext> context = new AsyncLocal<ServerCallContext>();
+
+        public static ServerCallContext Current {
+            get { return context.Value; }
+            set { context.Value = value; }
+        }
+    }
+}

+ 30 - 0
TEAMModelOS.SDK/Module/Grpc/Common/Internal/ServiceProviderAccessor.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Grpc.Extension.Common.Internal
+{
+    /// <summary>
+    /// ServiceProviderAccessor
+    /// </summary>
+    public class ServiceProviderAccessor
+    {
+        public static IServiceProvider ServiceProvider { get; private set; }
+
+        public static void SetServiceProvider(IServiceProvider sp)
+        {
+            ServiceProvider = sp;
+        }
+
+        public static T GetService<T>()
+        {
+            return ServiceProvider.GetService<T>();
+        }
+
+        public static List<T> GetServices<T>()
+        {
+            return ServiceProvider.GetServices<T>()?.ToList();
+        }
+    }
+}

+ 126 - 0
TEAMModelOS.SDK/Module/Grpc/Common/JsonSerialization.cs

@@ -0,0 +1,126 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// JsonSerialization
+    /// </summary>
+    public static class JsonSerialization
+    {
+        static JsonSerializerSettings settings = new JsonSerializerSettings()
+        {
+            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
+            PreserveReferencesHandling = PreserveReferencesHandling.Objects
+        };
+
+        /// <summary>
+        /// 使用json序列化为字符串
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="dateTimeFormat">默认null,即使用json.net默认的序列化机制,如:"\/Date(1439335800000+0800)\/"</param>
+        /// <param name="ignoreNullValue"></param>
+        /// <param name="isIndented"></param>
+        /// <returns></returns>
+        public static string ToJson(this object input, string dateTimeFormat = "yyyy-MM-dd HH:mm:ss", bool ignoreNullValue = true, bool isIndented = false)
+        {
+            settings.NullValueHandling = ignoreNullValue ? Newtonsoft.Json.NullValueHandling.Ignore : NullValueHandling.Include;
+
+            if (!string.IsNullOrWhiteSpace(dateTimeFormat))
+            {
+                var jsonConverter = new List<JsonConverter>()
+                {
+                    new Newtonsoft.Json.Converters.IsoDateTimeConverter(){ DateTimeFormat = dateTimeFormat }//如: "yyyy-MM-dd HH:mm:ss"
+                };
+                settings.Converters = jsonConverter;
+            }
+
+            //no format
+            var format = isIndented ? Newtonsoft.Json.Formatting.Indented : Formatting.None;
+            var json = JsonConvert.SerializeObject(input, format, settings);
+            return json;
+        }
+
+        /// <summary>
+        /// 从序列化字符串里反序列化
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="input"></param>
+        /// <param name="dateTimeFormat">默认null,即使用json.net默认的序列化机制</param>
+        /// <param name="ignoreNullValue"></param>
+        /// <returns></returns>
+        public static T TryFromJson<T>(this string input, string dateTimeFormat = "yyyy-MM-dd HH:mm:ss", bool ignoreNullValue = true)
+        {
+            try
+            {
+                return input.FromJson<T>(dateTimeFormat, ignoreNullValue);
+            }
+            catch
+            {
+                return default(T);
+            }
+        }
+        /// <summary>
+        /// 从序列化字符串里反序列化
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="input"></param>
+        /// <param name="dateTimeFormat">默认null,即使用json.net默认的序列化机制</param>
+        /// <param name="ignoreNullValue"></param>
+        /// <returns></returns>
+        public static T FromJson<T>(this string input, string dateTimeFormat = "yyyy-MM-dd HH:mm:ss", bool ignoreNullValue = true)
+        {
+            var settings = new JsonSerializerSettings()
+            {
+                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
+                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
+            };
+            settings.NullValueHandling = ignoreNullValue ? Newtonsoft.Json.NullValueHandling.Ignore : NullValueHandling.Include;
+
+            if (!string.IsNullOrWhiteSpace(dateTimeFormat))
+            {
+                var jsonConverter = new List<JsonConverter>()
+                {
+                    new Newtonsoft.Json.Converters.IsoDateTimeConverter(){ DateTimeFormat = dateTimeFormat }//如: "yyyy-MM-dd HH:mm:ss"
+                };
+                settings.Converters = jsonConverter;
+            }
+
+            return JsonConvert.DeserializeObject<T>(input, settings);
+        }
+        /// <summary>
+        /// 从序列化字符串里反序列化
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="type"></param>
+        /// <param name="dateTimeFormat">默认null,即使用json.net默认的序列化机制</param>
+        /// <param name="ignoreNullValue"></param>
+        /// <returns></returns>
+        public static object FromJson(this string input, Type type, string dateTimeFormat = "yyyy-MM-dd HH:mm:ss", bool ignoreNullValue = true)
+        {
+            var settings = new JsonSerializerSettings()
+            {
+                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
+                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
+            };
+            if (ignoreNullValue)
+            {
+                settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
+            }
+
+            if (!string.IsNullOrWhiteSpace(dateTimeFormat))
+            {
+                var jsonConverter = new List<JsonConverter>()
+                {
+                    new Newtonsoft.Json.Converters.IsoDateTimeConverter(){ DateTimeFormat = dateTimeFormat }//如: "yyyy-MM-dd HH:mm:ss"
+                };
+                settings.Converters = jsonConverter;
+            }
+
+            return JsonConvert.DeserializeObject(input, type, settings);
+        }
+    }
+}

+ 104 - 0
TEAMModelOS.SDK/Module/Grpc/Common/NetHelper.cs

@@ -0,0 +1,104 @@
+using System;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// NetHelper
+    /// </summary>
+    public static class NetHelper
+    {
+        /// <summary>
+        /// The ip segment regex
+        /// </summary>
+        private const string IPSegmentRegex = @"\d{0,3}";
+
+        /// <summary>
+        /// Gets the ip.
+        /// </summary>
+        /// <param name="ipSegment">ip段</param>
+        /// <returns></returns>
+        public static string GetIp(string ipSegment)
+        {
+            if (string.IsNullOrWhiteSpace(ipSegment))
+                throw new ArgumentNullException(nameof(ipSegment));
+
+            //如果设置的IP支持* 的时候,再去智能的选择ip
+            if (!ipSegment.Contains("*"))
+            {
+                return ipSegment;
+            }
+
+            ipSegment = ipSegment.Replace("*", IPSegmentRegex).Replace(".", "\\.");
+
+            var hostAddrs = NetworkInterface.GetAllNetworkInterfaces()
+            .Where(i => i.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
+                .SelectMany(i => i.GetIPProperties().UnicastAddresses)
+                .Select(a => a.Address)
+                .Where(a => !(a.IsIPv6LinkLocal || a.IsIPv6Multicast || a.IsIPv6SiteLocal || a.IsIPv6Teredo))
+                .ToList();
+
+            foreach (var ip in hostAddrs)
+            {
+                if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
+                    && System.Text.RegularExpressions.Regex.IsMatch(ip.ToString(), ipSegment))
+                {
+                    return ip.ToString();
+                }
+            }
+
+            throw new Exception($"找不到ipsegement:{ipSegment}匹配的ip, OR No network adapters with an IPv4 address in the system!");
+        }
+
+        /// <summary>
+        /// 解析ip和port
+        /// </summary>
+        /// <param name="serviceAddress"></param>
+        /// <returns></returns>
+        public static Tuple<string,int> GetIPAndPort(string serviceAddress)
+        {
+            //解析ip
+            var ipPort = serviceAddress.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
+            var ip = NetHelper.GetIp(ipPort[0]);
+            //解析port
+            var port = 0;
+            if (ipPort.Length == 2) int.TryParse(ipPort[1], out port);
+            //随机端口
+            if (port == 0) port = GetAvailablePort();
+            return Tuple.Create(ip, port);
+        }
+
+        /// <summary>
+        /// 获取本地ip
+        /// </summary>
+        /// <returns></returns>
+        public static string GetLocalIp()
+        {
+            string localIP;
+            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
+            {
+                socket.Connect("8.8.8.8", 65530);
+                IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
+                localIP = endPoint.Address.ToString();
+            }
+
+            return localIP;
+        }
+
+        /// <summary>
+        /// 获取可用端口
+        /// </summary>
+        /// <returns></returns>
+        public static int GetAvailablePort()
+        {
+            TcpListener l = new TcpListener(IPAddress.Loopback, 0);
+            l.Start();
+            int port = ((IPEndPoint)l.LocalEndpoint).Port;
+            l.Stop();
+            return port;
+        }
+    }
+}

+ 43 - 0
TEAMModelOS.SDK/Module/Grpc/Common/ObjectExtensions.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Grpc.Extension.Common
+{
+    internal static class ObjectExtensions
+    {
+        public static object FillProp(this object src)
+        {
+            foreach (var p in src.GetType().GetTypeInfo().GetProperties())
+            {
+                try
+                {
+                    if (p.PropertyType.GetTypeInfo().IsPrimitive ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(string)) ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(DateTime)) ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(Decimal)) ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(Guid)) ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(DateTimeOffset)) ||
+                        p.PropertyType.GetTypeInfo().Equals(typeof(TimeSpan)))
+                    {
+                        continue;
+                    }
+
+                    if (GrpcExtensionsOptions.Instance.FillPropExcludePrefixs.Any(q => p.PropertyType.GetTypeInfo().FullName.StartsWith(q)))
+                    {
+                        continue;
+                    }
+
+                    var subSrc = Activator.CreateInstance(p.PropertyType);
+                    subSrc = FillProp(subSrc);
+                    p.SetValue(src, subSrc);
+                }
+                catch
+                {
+                    continue;
+                }
+            }
+            return src;
+        }
+    }
+}

+ 43 - 0
TEAMModelOS.SDK/Module/Grpc/Common/Options/GrpcExtensionsOptions.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+
+namespace Grpc.Extension
+{
+    /// <summary>
+    /// GrpcServerOptions
+    /// </summary>
+    public class GrpcExtensionsOptions
+    {
+        private static Lazy<GrpcExtensionsOptions> instance = new Lazy<GrpcExtensionsOptions>(() => new GrpcExtensionsOptions(), true);
+        public static GrpcExtensionsOptions Instance => instance.Value;
+
+        private GrpcExtensionsOptions()
+        {
+        }
+
+        /// <summary>
+        /// grpc服务的包名
+        /// </summary>
+        public string GlobalPackage { get; set; }
+        /// <summary>
+        /// grpc服务的对外服务名
+        /// </summary>
+        public string GlobalService { get; set; }
+        /// <summary>
+        /// 是否输出响应内容
+        /// </summary>
+        public bool GlobalSaveResponseEnable { get; set; } = false;
+        /// <summary>
+        /// 生成proto文件的c#命名空间
+        /// </summary>
+        public string ProtoNameSpace { get; set; }
+        /// <summary>
+        /// 是否为基础服务生成proto文件
+        /// </summary>
+        public bool GenBaseServiceProtoEnable = false;
+        /// <summary>
+        /// 生成Json对象时排除前缀
+        /// </summary>
+        internal List<string> FillPropExcludePrefixs { get; set; } = new List<string> { "Google." };
+    }
+}

+ 41 - 0
TEAMModelOS.SDK/Module/Grpc/Common/ProtobufExtensions.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using ProtoBuf;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// ProtobufExtensions
+    /// </summary>
+    public class ProtobufExtensions
+    {
+        /// <summary>
+        /// 序列化
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        public static byte[] Serialize<T>(T input)
+        {
+            using (MemoryStream memoryStream = new MemoryStream())
+            {
+                Serializer.Serialize<T>((Stream)memoryStream, input);
+                return memoryStream.ToArray();
+            }
+        }
+
+        /// <summary>
+        /// 反序列化
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        public static T Deserialize<T>(byte[] data)
+        {
+            using (MemoryStream memoryStream = new MemoryStream(data))
+                return Serializer.Deserialize<T>((Stream)memoryStream);
+        }
+    }
+}

+ 82 - 0
TEAMModelOS.SDK/Module/Grpc/Common/ReflectorExtensions.cs

@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using AspectCore.Extensions.Reflection;
+
+namespace Grpc.Extension.Common
+{
+    /// <summary>
+    /// ReflectorExtensions
+    /// </summary>
+    public static class ReflectorExtensions
+    {
+        /// <summary>
+        /// 获取属性值
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj"></param>
+        /// <param name="name"></param>
+        /// <param name="bindingFlags"></param>
+        /// <returns></returns>
+        public static T GetPropertyValue<T>(this object obj, string name, BindingFlags bindingFlags) where T : class
+        {
+            var chProperty = obj.GetType().GetTypeInfo().GetProperty(name, bindingFlags);
+            if (chProperty == null) throw new InvalidOperationException($"Cannot locate property {name}");
+            var chReflector = chProperty.GetReflector();
+            var value = chReflector.GetValue(obj) as T;
+
+            return value;
+        }
+
+        /// <summary>
+        /// 获取字段值
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj"></param>
+        /// <param name="name"></param>
+        /// <param name="bindingFlags"></param>
+        /// <returns></returns>
+        public static Tuple<T, FieldInfo> GetFieldValue<T>(this object obj, string name, BindingFlags bindingFlags) where T : class
+        {
+            var chField = obj.GetType().GetTypeInfo().GetField(name, bindingFlags);
+            if (chField == null) throw new InvalidOperationException($"Cannot locate field {name}");
+            var chReflector = chField.GetReflector();
+            var value = chReflector.GetValue(obj) as T;
+
+            return Tuple.Create(value, chField);
+        }
+
+        /// <summary>
+        /// 获取字段值
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="type"></param>
+        /// <param name="name"></param>
+        /// <param name="bindingFlags"></param>
+        /// <returns></returns>
+        public static T GetFieldValue<T>(this Type type, string name, BindingFlags bindingFlags) where T : class
+        {
+            var chField = type.GetTypeInfo().GetField(name, bindingFlags);
+            if (chField == null) throw new InvalidOperationException($"Cannot locate field {name}");
+            var chReflector = chField.GetReflector();
+            var value = chReflector.GetValue(null) as T;
+
+            return value;
+        }
+
+        /// <summary>
+        /// 获取方法
+        /// </summary>
+        /// <param name="type"></param>
+        /// <param name="name"></param>
+        /// <param name="bindingFlags"></param>
+        /// <returns></returns>
+        public static MethodInfo GetMethodInfo(this Type type, string name, BindingFlags bindingFlags)
+        {
+            var method = type.GetMethod(name, bindingFlags);
+            if(method == null) throw new InvalidOperationException($"Cannot locate method {name}");
+            return method;
+        }
+    }
+}

+ 32 - 0
TEAMModelOS.SDK/Module/Grpc/Discovery/Consul/ConsulServiceDiscovery.cs

@@ -0,0 +1,32 @@
+using Consul;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Collections.Concurrent;
+using Grpc.Extension.Abstract.Discovery;
+
+namespace Grpc.Extension.Discovery.Consul
+{
+    /// <summary>
+    /// Consul服务发现
+    /// </summary>
+    public class ConsulServiceDiscovery : IServiceDiscovery
+    {
+        private ConcurrentDictionary<string, ConsulClient> _consulClients = new ConcurrentDictionary<string, ConsulClient>();
+
+        /// <summary>
+        /// 从consul获取可用的节点信息
+        /// </summary>
+        public List<string> GetEndpoints(string serviceName, string consulUrl, string consulTag)
+        {
+            var client = CreateConsulClient(consulUrl);
+            var res = client.Health.Service(serviceName, consulTag , true).Result;
+            return res.Response.Select(q => $"{q.Service.Address}:{q.Service.Port}").ToList();
+        }        
+        
+        private ConsulClient CreateConsulClient(string consulUrl)
+        {
+            return _consulClients.GetOrAdd(consulUrl, (url) => new ConsulClient(conf => conf.Address = new Uri(url)));
+        }
+    }
+}

+ 129 - 0
TEAMModelOS.SDK/Module/Grpc/Discovery/Consul/ConsulServiceRegister.cs

@@ -0,0 +1,129 @@
+using Consul;
+using Grpc.Extension.Abstract;
+using Grpc.Extension.Abstract.Discovery;
+using Grpc.Extension.Abstract.Model;
+using System;
+using System.Threading;
+
+namespace Grpc.Extension.Discovery.Consul
+{
+    /// <summary>
+    /// Consul服务注册
+    /// </summary>
+    public class ConsulServiceRegister : IServiceRegister
+    {
+        private Timer _timerTTL;
+        private string _guid;
+        private ConsulClient _client;
+        private ServiceRegisterModel _model;
+
+        /// <summary>
+        /// Consul服务注册
+        /// </summary>
+        public ConsulServiceRegister()
+        {
+            this._guid = Guid.NewGuid().ToString();
+        }
+
+        /// <summary>
+        /// 注册服务到consul
+        /// </summary>
+        /// <param name="ip"></param>
+        /// <param name="port"></param>
+        public void RegisterService(ServiceRegisterModel model)
+        {
+            this._model = model;
+            this._client = CreateConsulClient();
+
+            RegisterServiceCore();
+
+            //因为公司的consul不支持consul主动检查服务状态,所以启动定时器主动去检测
+            _timerTTL = new Timer(state => DoTTL(), null, Timeout.Infinite, Timeout.Infinite);
+            DoTTL();
+        }
+
+        private void RegisterServiceCore()
+        {
+            var registration = new AgentServiceRegistration()
+            {
+                ID = GetServiceId(),
+                Name = _model.DiscoveryServiceName,
+                Tags = _model.DiscoveryServiceTags?.Split(','),
+                EnableTagOverride = true,
+                Address = _model.ServiceIp,
+                Port = _model.ServicePort,
+                //因为公司的consul不支持consul主动检查服务状态,所以注释掉
+                //Check = new AgentServiceCheck
+                //{
+                //    TCP = $"{_model.ServiceIp}:{_model.ServicePort}",
+                //    Interval = TimeSpan.FromSeconds(15),
+                //    Status = HealthStatus.Passing,
+                //    DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1)
+                //}
+                //因为公司的consul不支持consul主动检查服务状态,所以主动去TTL consul
+                Check = new AgentCheckRegistration
+                {
+                    ID = GetTTLCheckId(),
+                    Name = "ttlcheck",
+                    TTL = TimeSpan.FromSeconds(15),
+                    Status = HealthStatus.Passing,
+                    DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1),
+                }
+            };
+            _client.Agent.ServiceRegister(registration).Wait();
+        }
+
+        /// <summary>
+        /// 从consul反注册
+        /// </summary>
+        public void DeregisterService()
+        {
+            _client.Agent.ServiceDeregister(GetServiceId()).Wait();
+        }
+
+        private string GetServiceId()
+        {
+            return $"{_model.DiscoveryServiceName}-{(_model.ServiceIp)}-{(_model.ServicePort)}-{_guid}";
+        }
+
+        private string GetTTLCheckId()
+        {
+            return $"service:{GetServiceId()}";
+        }
+
+        private void DoTTL()
+        {
+            _timerTTL.Change(Timeout.Infinite, Timeout.Infinite);
+            try
+            {
+                _client.Agent.PassTTL(GetTTLCheckId(), "timer:" + DateTime.Now).Wait();
+            }
+            catch (Exception ex)
+            {
+                LoggerAccessor.Instance.OnLoggerError(new InternalException(GrpcErrorCode.Internal, "DoTTL", ex));
+
+                /*
+                 * passTTL会出现如下几种情况:
+                 * 1. consul服务重启中,ex会显示 connection refused by ip:port
+                 *          这种情况下,不去处理,等consul服务重启之后就好了
+                 * 2. consul服务重启之后,会丢失之前的service,check,会有如下的错误:
+                 *          Unexpected response, status code InternalServerError: CheckID "followme.srv.sms-192.168.3.10-10086-07f21040-0be9-4a73-b0a1-71755c6d6d46:ttlcheck" does not have associated TTL
+                 *          在这种情况下,需要处理,重新注册服务,check;     
+                 */
+                if (ex.ToString().Contains($"CheckID \"{GetTTLCheckId()}\" does not have associated TTL"))
+                {
+                    RegisterServiceCore();
+                }
+            }
+            finally
+            {
+                _timerTTL.Change(TimeSpan.FromSeconds(_model.DiscoveryTTLInterval), TimeSpan.FromSeconds(_model.DiscoveryTTLInterval));
+            }
+        }
+
+        private ConsulClient CreateConsulClient()
+        {
+            return new ConsulClient(conf => conf.Address = new Uri(_model.DiscoveryUrl));
+        }
+    }
+}

+ 25 - 0
TEAMModelOS.SDK/Module/Grpc/Discovery/ServiceCollectionExtensions.cs

@@ -0,0 +1,25 @@
+using Grpc.Extension.Abstract.Discovery;
+using Grpc.Extension.Discovery.Consul;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Grpc.Extension.Discovery
+{
+    /// <summary>
+    /// 添加服务注册,服务发现
+    /// </summary>
+    public static class ServiceCollectionExtensions
+    {
+        /// <summary>
+        /// 添加服务注册,服务发现
+        /// </summary>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        public static IServiceCollection AddConsulDiscovery(this IServiceCollection services)
+        {
+            services.AddSingleton<IServiceRegister, ConsulServiceRegister>();
+            services.AddSingleton<IServiceDiscovery, ConsulServiceDiscovery>();
+
+            return services;
+        }
+    }
+}

+ 23 - 14
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <Version>2.0.7</Version>
     <Version>2.0.7</Version>
     <AssemblyVersion>2.0.0.7</AssemblyVersion>
     <AssemblyVersion>2.0.0.7</AssemblyVersion>
     <FileVersion>2.0.0.7</FileVersion>
     <FileVersion>2.0.0.7</FileVersion>
@@ -9,29 +9,38 @@
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="AspectCore.Extensions.Reflection" Version="1.3.0" />
+    <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.1.0" />
     <PackageReference Include="ClouDASLibx" Version="1.1.4" />
     <PackageReference Include="ClouDASLibx" Version="1.1.4" />
+    <PackageReference Include="Consul" Version="0.7.2.6" />
     <PackageReference Include="DocumentFormat.OpenXml" Version="2.10.1" />
     <PackageReference Include="DocumentFormat.OpenXml" Version="2.10.1" />
-    <PackageReference Include="HtmlAgilityPack" Version="1.11.16" />
-    <PackageReference Include="IdentityModel" Version="4.0.0" />
-    <PackageReference Include="LiteDB" Version="4.1.4" />
+    <PackageReference Include="Grpc.AspNetCore.Server" Version="2.27.0" />
+    <PackageReference Include="Grpc.Core" Version="2.27.0" />
+    <PackageReference Include="HtmlAgilityPack" Version="1.11.23" />
+    <PackageReference Include="IdentityModel" Version="4.2.0" />
+    <PackageReference Include="Jaeger" Version="0.3.7" />
+    <PackageReference Include="LiteDB" Version="5.0.5" />
     <PackageReference Include="log4net" Version="2.0.8" />
     <PackageReference Include="log4net" Version="2.0.8" />
-    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
-    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
+    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.3" />
     <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
     <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
-    <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="3.1.2" />
-    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="3.1.3" />
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
     <PackageReference Include="Microsoft.Azure.CosmosDB.BulkExecutor" Version="2.4.1-preview" />
     <PackageReference Include="Microsoft.Azure.CosmosDB.BulkExecutor" Version="2.4.1-preview" />
-    <PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.9.2" />
+    <PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.10.1" />
+    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
     <PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
     <PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
-    <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.0.0" />
-    <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="5.6.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.3" />
+    <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.5.0" />
+    <PackageReference Include="OpenTracing" Version="0.12.1" />
+    <PackageReference Include="protobuf-net" Version="2.4.6" />
     <PackageReference Include="Scrutor" Version="3.2.0" />
     <PackageReference Include="Scrutor" Version="3.2.0" />
     <PackageReference Include="System.Drawing.Common" Version="4.7.0" />
     <PackageReference Include="System.Drawing.Common" Version="4.7.0" />
-    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.6.0" />
+    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.5.0" />
     <PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
     <PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
     <PackageReference Include="XC.Framework.Security.RSAUtil" Version="1.0.1" />
     <PackageReference Include="XC.Framework.Security.RSAUtil" Version="1.0.1" />
-    <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.6.0" />
+    <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.8.0" />
     <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="2.0.0-preview" />
     <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="2.0.0-preview" />
     <PackageReference Include="Caching.CSRedis" Version="3.5.5" />
     <PackageReference Include="Caching.CSRedis" Version="3.5.5" />
   </ItemGroup>
   </ItemGroup>

+ 2 - 2
TEAMModelOS.Service/Services/PowerPoint/Implement/HtexService.cs

@@ -1389,7 +1389,7 @@ namespace TEAMModelOS.Service.Services.PowerPoint.Implement
                 }
                 }
                 else if (ShapeType.Equals("CxnSp"))
                 else if (ShapeType.Equals("CxnSp"))
                 {
                 {
-                    string bdsha = null;
+                    //string bdsha = null;
                     //if (shapeBorder != null && shapeBorder.Type != null)
                     //if (shapeBorder != null && shapeBorder.Type != null)
                     //{
                     //{
                     //    bdsha = ShaHashHelper.GetSHA1(shapeBorder.ToJson());
                     //    bdsha = ShaHashHelper.GetSHA1(shapeBorder.ToJson());
@@ -1908,7 +1908,7 @@ namespace TEAMModelOS.Service.Services.PowerPoint.Implement
                 dfltBultColor = GetFontColorPr(node, spNode, type, sldMstrTxtStyles, slideMasterContent, themeContent);
                 dfltBultColor = GetFontColorPr(node, spNode, type, sldMstrTxtStyles, slideMasterContent, themeContent);
                 dfltBultSize = GetFontSize(node, slideLayoutSpNode, slideMasterSpNode, type, sldMstrTxtStyles);
                 dfltBultSize = GetFontSize(node, slideLayoutSpNode, slideMasterSpNode, type, sldMstrTxtStyles);
             }
             }
-            var bullet = "";
+            //var bullet = "";
             var pPrNode = node.GetTextByPath("a:pPr");
             var pPrNode = node.GetTextByPath("a:pPr");
             var getRtlVal = node.GetTextByPath("a:pPr/@rtl");
             var getRtlVal = node.GetTextByPath("a:pPr/@rtl");
             var isRTL = false;
             var isRTL = false;

+ 1 - 1
TEAMModelOS.Service/TEAMModelOS.Service.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 6 - 0
TEAMModelOS.sln

@@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS", "TEAMModelOS\
 EndProject
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.Service", "TEAMModelOS.Service\TEAMModelOS.Service.csproj", "{04508AB6-CD54-46B4-B96D-9672EB66761B}"
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.Service", "TEAMModelOS.Service\TEAMModelOS.Service.csproj", "{04508AB6-CD54-46B4-B96D-9672EB66761B}"
 EndProject
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.GRPC", "TEAMModelOS.GRPC\TEAMModelOS.GRPC.csproj", "{B000D9E3-C412-4BD5-8459-08232A962665}"
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Release|Any CPU.Build.0 = Release|Any CPU
 		{04508AB6-CD54-46B4-B96D-9672EB66761B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B000D9E3-C412-4BD5-8459-08232A962665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B000D9E3-C412-4BD5-8459-08232A962665}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B000D9E3-C412-4BD5-8459-08232A962665}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B000D9E3-C412-4BD5-8459-08232A962665}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE

+ 4 - 5
TEAMModelOS/TEAMModelOS.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <PropertyGroup>
   <PropertyGroup>
@@ -13,11 +13,10 @@
     <PackageReference Include="Bogus" Version="29.0.1" />
     <PackageReference Include="Bogus" Version="29.0.1" />
     <PackageReference Include="Caching.CSRedis" Version="3.5.5" />
     <PackageReference Include="Caching.CSRedis" Version="3.5.5" />
     <PackageReference Include="CSRedisCore" Version="3.5.5" />
     <PackageReference Include="CSRedisCore" Version="3.5.5" />
-    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
-    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
-    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.3" />
+    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.2" />
     <PackageReference Include="VueCliMiddleware" Version="3.0.0" />
     <PackageReference Include="VueCliMiddleware" Version="3.0.0" />
-    <PackageReference Include="EdjCase.JsonRpc.Router.Extension" Version="4.0.1" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <!-- Don't publish the SPA source files, but do show them in the project files list -->
     <!-- Don't publish the SPA source files, but do show them in the project files list -->