黄贺彬 5 tahun lalu
induk
melakukan
1dde7c7442
100 mengubah file dengan 4508 tambahan dan 103 penghapusan
  1. 2 0
      ConsoleApp1/Program.cs
  2. 13 0
      ConsoleApp5AliOSS/ConsoleApp5AliOSS.csproj
  3. 53 0
      ConsoleApp5AliOSS/Program.cs
  4. 39 0
      EasyRpc/Controllers/WeatherForecastController.cs
  5. 12 0
      EasyRpc/EasyRpc.csproj
  6. 44 0
      EasyRpc/Interfaces/IIntMath.cs
  7. 26 0
      EasyRpc/Program.cs
  8. 30 0
      EasyRpc/Properties/launchSettings.json
  9. 64 0
      EasyRpc/Services/IntMath.cs
  10. 59 0
      EasyRpc/Startup.cs
  11. 15 0
      EasyRpc/WeatherForecast.cs
  12. 9 0
      EasyRpc/appsettings.Development.json
  13. 10 0
      EasyRpc/appsettings.json
  14. 97 0
      JsonRPC4/Builder/BuilderExtensions.cs
  15. 17 0
      JsonRPC4/Builder/IRpcBuilder.cs
  16. 21 0
      JsonRPC4/Builder/RpcBuilder.cs
  17. 54 0
      JsonRPC4/Builder/RpcBuilderExtensions.cs
  18. 11 0
      JsonRPC4/Builder/RpcServicesMarker.cs
  19. 28 0
      JsonRPC4/Common/JsonRpcContants.cs
  20. 66 0
      JsonRPC4/Common/RpcError.cs
  21. 16 0
      JsonRPC4/Common/RpcErrorCode.cs
  22. 43 0
      JsonRPC4/Common/RpcException.cs
  23. 167 0
      JsonRPC4/Common/RpcId.cs
  24. 13 0
      JsonRPC4/Common/RpcIdType.cs
  25. 29 0
      JsonRPC4/Common/Tools/DefaultStreamCompressor.cs
  26. 14 0
      JsonRPC4/Common/Tools/IStreamCompressor.cs
  27. 27 0
      JsonRPC4/Common/Utilities/TypeExtensions.cs
  28. 13 0
      JsonRPC4/Controllers/Item.cs
  29. 57 0
      JsonRPC4/Controllers/WeatherForecastController.cs
  30. 26 0
      JsonRPC4/IRouteContext.cs
  31. 14 0
      JsonRPC4/IRpcMethodProvider.cs
  32. 8 0
      JsonRPC4/JsonRPC4.csproj
  33. 26 0
      JsonRPC4/Program.cs
  34. 30 0
      JsonRPC4/Properties/launchSettings.json
  35. 14 0
      JsonRPC4/Router/Abstractions/IRpcInvoker.cs
  36. 13 0
      JsonRPC4/Router/Abstractions/IRpcMethodResult.cs
  37. 14 0
      JsonRPC4/Router/Abstractions/IRpcParser.cs
  38. 13 0
      JsonRPC4/Router/Abstractions/IRpcRequestHandler.cs
  39. 14 0
      JsonRPC4/Router/Abstractions/IRpcRequestMatcher.cs
  40. 15 0
      JsonRPC4/Router/Abstractions/IRpcResponseSerializer.cs
  41. 20 0
      JsonRPC4/Router/Abstractions/RpcParserExtensions.cs
  42. 28 0
      JsonRPC4/Router/Abstractions/RpcRequestHandlerExtensions.cs
  43. 35 0
      JsonRPC4/Router/Abstractions/RpcResponseSerializerExtensions.cs
  44. 473 0
      JsonRPC4/Router/Defaults/DefaultRequestMatcher.cs
  45. 40 0
      JsonRPC4/Router/Defaults/DefaultRouteContext.cs
  46. 272 0
      JsonRPC4/Router/Defaults/DefaultRpcInvoker.cs
  47. 283 0
      JsonRPC4/Router/Defaults/DefaultRpcParser.cs
  48. 113 0
      JsonRPC4/Router/Defaults/DefaultRpcResponseSerializer.cs
  49. 18 0
      JsonRPC4/Router/Defaults/JsonBytesSequenceSegment.cs
  50. 24 0
      JsonRPC4/Router/Defaults/RpcEndpointInfo.cs
  51. 37 0
      JsonRPC4/Router/Defaults/RpcMethodErrorResult.cs
  52. 25 0
      JsonRPC4/Router/Defaults/RpcMethodSuccessResult.cs
  53. 18 0
      JsonRPC4/Router/IRpcParameter.cs
  54. 53 0
      JsonRPC4/Router/JsonBytesRpcParameter.cs
  55. 47 0
      JsonRPC4/Router/OnExceptionResult.cs
  56. 54 0
      JsonRPC4/Router/ParsingResult.cs
  57. 60 0
      JsonRPC4/Router/RawRpcParameter.cs
  58. 15 0
      JsonRPC4/Router/RpcCanceledRequestException.cs
  59. 15 0
      JsonRPC4/Router/RpcConfigurationException.cs
  60. 22 0
      JsonRPC4/Router/RpcController.cs
  61. 88 0
      JsonRPC4/Router/RpcEndpointBuilder.cs
  62. 13 0
      JsonRPC4/Router/RpcErrorFilterAttribute.cs
  63. 109 0
      JsonRPC4/Router/RpcHttpRouter.cs
  64. 28 0
      JsonRPC4/Router/RpcMethodInfo.cs
  65. 21 0
      JsonRPC4/Router/RpcParameterExtensions.cs
  66. 15 0
      JsonRPC4/Router/RpcParameterType.cs
  67. 64 0
      JsonRPC4/Router/RpcParameters.cs
  68. 220 0
      JsonRPC4/Router/RpcPath.cs
  69. 33 0
      JsonRPC4/Router/RpcRequest.cs
  70. 122 0
      JsonRPC4/Router/RpcRequestHandler.cs
  71. 50 0
      JsonRPC4/Router/RpcRequestParseResult.cs
  72. 60 0
      JsonRPC4/Router/RpcResponse.cs
  73. 17 0
      JsonRPC4/Router/RpcRouteAttribute.cs
  74. 33 0
      JsonRPC4/Router/RpcRouteInfo.cs
  75. 14 0
      JsonRPC4/Router/RpcRouterException.cs
  76. 30 0
      JsonRPC4/Router/RpcServerConfiguration.cs
  77. 44 0
      JsonRPC4/Router/StaticRpcMethodProvider.cs
  78. 198 0
      JsonRPC4/Router/Utilities/LoggerExtensions.cs
  79. 17 0
      JsonRPC4/Router/Utilities/RouteContextExtensions.cs
  80. 45 0
      JsonRPC4/Router/Utilities/RpcUtil.cs
  81. 20 0
      JsonRPC4/Router/Utilities/StreamUtil.cs
  82. 20 0
      JsonRPC4/Router/Utilities/TypeExtensions.cs
  83. 47 0
      JsonRPC4/Startup.cs
  84. 15 0
      JsonRPC4/WeatherForecast.cs
  85. 9 0
      JsonRPC4/appsettings.Development.json
  86. 10 0
      JsonRPC4/appsettings.json
  87. 25 1
      NETCore3Demo.sln
  88. 13 0
      WebTest/Controllers/Item.cs
  89. 13 0
      WebTest/Controllers/Person.cs
  90. 55 100
      WebTest/Controllers/WeatherForecastController.cs
  91. 13 0
      WebTest/JsonRPC/BaseJosnRPCRequest.cs
  92. 13 0
      WebTest/JsonRPC/JosnRPCReq.cs
  93. 13 0
      WebTest/JsonRPC/JosnRPCRequest.cs
  94. 3 1
      WebTest/Startup.cs
  95. 5 1
      WebTest/WebTest.csproj
  96. 13 0
      aspnetcore-json-rpc/Controllers/Item.cs
  97. 56 0
      aspnetcore-json-rpc/Controllers/WeatherForecastController.cs
  98. 26 0
      aspnetcore-json-rpc/Program.cs
  99. 30 0
      aspnetcore-json-rpc/Properties/launchSettings.json
  100. 0 0
      aspnetcore-json-rpc/Startup.cs

+ 2 - 0
ConsoleApp1/Program.cs

@@ -9,6 +9,8 @@ namespace ConsoleApp1
         static void Main(string[] args)
         {
 
+            var a = 500 / 26000.00;
+
             StaticDelegateDemo();
             InstanceDelegateDemo();
             Console.ReadKey();

+ 13 - 0
ConsoleApp5AliOSS/ConsoleApp5AliOSS.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
+    <PackageReference Include="Aliyun.SDK.CCP.OSS.Client" Version="0.0.4" />
+  </ItemGroup>
+
+</Project>

+ 53 - 0
ConsoleApp5AliOSS/Program.cs

@@ -0,0 +1,53 @@
+using Aliyun.OSS;
+using Aliyun.OSS.Common;
+using System;
+using System.Collections.Generic;
+
+namespace ConsoleApp5AliOSS
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            // Endpoint以杭州为例,其它Region请按实际情况填写。
+            String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";
+            // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
+            String accessKeyId = "LTAI4FsANPbYKsxD6rWB8ShJ";
+            String accessKeySecret = "fxQ6VHiEQtwH3MjlGeCoCWYeViqzkA";
+            String bucketName = "hystkj-oss";
+            // 创建ClientConfiguration实例,按照您的需要修改默认参数。
+            var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
+            try
+            {
+                var objects = new List<string>();
+                ObjectListing result = null;
+                string nextMarker = string.Empty;
+                do
+                {
+                    var listObjectsRequest = new ListObjectsRequest(bucketName)
+                    {
+                        Marker = nextMarker,
+                    };
+                    // 列举文件。
+                    result = client.ListObjects(listObjectsRequest);
+                    foreach (var summary in result.ObjectSummaries)
+                    {
+                        Console.WriteLine(summary.Key);
+                        objects.Add(summary.Key);
+                    }
+                    nextMarker = result.NextMarker;
+                } while (result.IsTruncated);
+                Console.WriteLine("List objects of bucket:{0} succeeded ", bucketName);
+            }
+            catch (OssException ex)
+            {
+                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
+                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("Failed with error info: {0}", ex.Message);
+            }
+        }
+    }
+}

+ 39 - 0
EasyRpc/Controllers/WeatherForecastController.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+namespace EasyRpc.Controllers
+{
+    [ApiController]
+    [Route("[controller]")]
+    public class WeatherForecastController : ControllerBase
+    {
+        private static readonly string[] Summaries = new[]
+        {
+            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+        };
+
+        private readonly ILogger<WeatherForecastController> _logger;
+
+        public WeatherForecastController(ILogger<WeatherForecastController> logger)
+        {
+            _logger = logger;
+        }
+
+        [HttpGet]
+        public IEnumerable<WeatherForecast> Get()
+        {
+            var rng = new Random();
+            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+            {
+                Date = DateTime.Now.AddDays(index),
+                TemperatureC = rng.Next(-20, 55),
+                Summary = Summaries[rng.Next(Summaries.Length)]
+            })
+            .ToArray();
+        }
+    }
+}

+ 12 - 0
EasyRpc/EasyRpc.csproj

@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="EasyRpc.AspNetCore" Version="4.0.0-Beta1109" />
+  </ItemGroup>
+
+
+</Project>

+ 44 - 0
EasyRpc/Interfaces/IIntMath.cs

@@ -0,0 +1,44 @@
+using EasyRpc.Services;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace EasyRpc.Interfaces
+{
+    public interface IIntMath
+    {
+        /// <summary>
+        /// Add to integers together
+        /// hello tanya
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        int Add(int x, int y);
+
+        /// <summary>
+        /// Subtract to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        int Subtract(Item item);
+
+        /// <summary>
+        /// Multiply to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        int Multiply(int x, int y);
+
+        /// <summary>
+        /// Divide to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        int Divide(int x, int y);
+    }
+}

+ 26 - 0
EasyRpc/Program.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace EasyRpc
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                });
+    }
+}

+ 30 - 0
EasyRpc/Properties/launchSettings.json

@@ -0,0 +1,30 @@
+{
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:52495",
+      "sslPort": 44370
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "EasyRpc": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 64 - 0
EasyRpc/Services/IntMath.cs

@@ -0,0 +1,64 @@
+using EasyRpc.Interfaces;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace EasyRpc.Services
+{
+
+    public class Item
+    {
+        public int a { get; set; }
+        public int b { get; set; }
+    }
+    public class IntMath// : IIntMath
+    {
+        /// <summary>
+        /// Add to integers together
+        /// hello tanya
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        public int Add(int x, int y)
+        {
+            return x + y;
+        }
+
+        /// <summary>
+        /// Subtract to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        public int Subtract(Item item ,Dictionary<string,int > dict)
+        {
+            return 5;
+        }
+
+        /// <summary>
+        /// Multiply to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        public int Multiply(int x, int y)
+        {
+            return x * y;
+        }
+
+        /// <summary>
+        /// Divide to integers together
+        /// </summary>
+        /// <param name="x">first integer</param>
+        /// <param name="y">second integer</param>
+        /// <returns></returns>
+        public int Divide(int x, int y)
+        {
+            return x / y;
+        }
+    }
+}

+ 59 - 0
EasyRpc/Startup.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using EasyRpc.AspNetCore;
+using EasyRpc.Services;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.HttpsPolicy;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace EasyRpc
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddJsonRpc();
+            services.AddControllers();
+        }
+
+        // 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.UseHttpsRedirection();
+
+            app.UseRouting();
+
+            app.UseAuthorization();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapControllers();
+            });
+            app.UseJsonRpc("/", api =>
+            {
+                // Expose methods at /IntMath
+                api.Expose<IntMath>().As("IntMath");
+            });
+        }
+    }
+}

+ 15 - 0
EasyRpc/WeatherForecast.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace EasyRpc
+{
+    public class WeatherForecast
+    {
+        public DateTime Date { get; set; }
+
+        public int TemperatureC { get; set; }
+
+        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+        public string Summary { get; set; }
+    }
+}

+ 9 - 0
EasyRpc/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}

+ 10 - 0
EasyRpc/appsettings.json

@@ -0,0 +1,10 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*"
+}

+ 97 - 0
JsonRPC4/Builder/BuilderExtensions.cs

@@ -0,0 +1,97 @@
+using JsonRPC4.Common.Tools;
+using JsonRPC4.Router;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Defaults;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Builder
+{
+	public static class BuilderExtensions
+	{
+		public static IRpcBuilder AddJsonRpc(this IServiceCollection serviceCollection)
+		{
+			if (serviceCollection == null)
+			{
+				throw new ArgumentNullException("serviceCollection");
+			}
+			serviceCollection.AddSingleton(new RpcServicesMarker());
+			serviceCollection.TryAddScoped<IRpcInvoker, DefaultRpcInvoker>();
+			serviceCollection.TryAddScoped<IRpcParser, DefaultRpcParser>();
+			serviceCollection.TryAddScoped<IRpcRequestHandler, RpcRequestHandler>();
+			serviceCollection.TryAddScoped<IStreamCompressor, DefaultStreamCompressor>();
+			serviceCollection.TryAddScoped<IRpcResponseSerializer, DefaultRpcResponseSerializer>();
+			serviceCollection.TryAddScoped<IRpcRequestMatcher, DefaultRequestMatcher>();
+			AuthorizationServiceCollectionExtensions.AddAuthorizationCore(serviceCollection.AddRouting());
+			return new RpcBuilder(serviceCollection);
+		}
+
+		public static IApplicationBuilder UseJsonRpc(this IApplicationBuilder app)
+		{
+			if (app == null)
+			{
+				throw new ArgumentNullException("app");
+			}
+			return app.UseJsonRpcWithBaseController<RpcController>();
+		}
+
+		public static IApplicationBuilder UseJsonRpcWithBaseController<T>(this IApplicationBuilder app)
+		{
+			if (app == null)
+			{
+				throw new ArgumentNullException("app");
+			}
+			return app.UseJsonRpc(delegate (RpcEndpointBuilder builder)
+			{
+				Type baseControllerType = typeof(T);
+				foreach (Type item in (IEnumerable<Type>)(from t in Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(Assembly.Load)
+						.SelectMany((Assembly x) => x.DefinedTypes)
+						.Concat(Assembly.GetEntryAssembly().DefinedTypes)
+														  where !t.IsAbstract && (t == baseControllerType || t.IsSubclassOf(baseControllerType))
+														  select t))
+				{
+					builder.AddControllerWithDefaultPath(item);
+				}
+			});
+		}
+
+		public static IApplicationBuilder UseJsonRpc(this IApplicationBuilder app, Action<RpcEndpointBuilder> builder)
+		{
+			if (app == null)
+			{
+				throw new ArgumentNullException("app");
+			}
+			if (builder == null)
+			{
+				throw new ArgumentNullException("builder");
+			}
+			RpcEndpointBuilder rpcEndpointBuilder = new RpcEndpointBuilder();
+			builder(rpcEndpointBuilder);
+			return app.UseJsonRpc(rpcEndpointBuilder.Resolve());
+		}
+
+		public static IApplicationBuilder UseJsonRpc(this IApplicationBuilder app, IRpcMethodProvider methodProvider)
+		{
+			if (app == null)
+			{
+				throw new ArgumentNullException("app");
+			}
+			if (methodProvider == null)
+			{
+				throw new ArgumentNullException("methodProvider");
+			}
+			if (app.ApplicationServices.GetService<RpcServicesMarker>() == null)
+			{
+				throw new InvalidOperationException("AddJsonRpc() needs to be called in the ConfigureServices method.");
+			}
+			RpcHttpRouter router = new RpcHttpRouter(methodProvider);
+			return app.UseRouter(router);
+		}
+	}
+}

+ 17 - 0
JsonRPC4/Builder/IRpcBuilder.cs

@@ -0,0 +1,17 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Builder
+{
+	public interface IRpcBuilder
+	{
+		IServiceCollection Services
+		{
+			get;
+		}
+	}
+
+}

+ 21 - 0
JsonRPC4/Builder/RpcBuilder.cs

@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Builder
+{
+	internal class RpcBuilder : IRpcBuilder
+	{
+		public IServiceCollection Services
+		{
+			get;
+		}
+
+		public RpcBuilder(IServiceCollection services)
+		{
+			Services = services;
+		}
+	}
+}

+ 54 - 0
JsonRPC4/Builder/RpcBuilderExtensions.cs

@@ -0,0 +1,54 @@
+using JsonRPC4.Common.Tools;
+using JsonRPC4.Router;
+using JsonRPC4.Router.Abstractions;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Builder
+{
+	public static class RpcBuilderExtensions
+	{
+		public static IRpcBuilder WithOptions(this IRpcBuilder builder, Action<RpcServerConfiguration> configureOptions)
+		{
+			RpcServerConfiguration obj = new RpcServerConfiguration();
+			configureOptions?.Invoke(obj);
+			builder.Services.Configure(configureOptions);
+			return builder;
+		}
+
+		public static IRpcBuilder WithOptions(this IRpcBuilder builder, RpcServerConfiguration configuration)
+		{
+			builder.Services.AddSingleton(Options.Create(configuration));
+			return builder;
+		}
+
+		public static IRpcBuilder WithParser<T>(this IRpcBuilder builder) where T : class, IRpcParser
+		{
+			builder.Services.AddScoped<IRpcParser, T>();
+			return builder;
+		}
+
+		public static IRpcBuilder WithCompressor<T>(this IRpcBuilder builder) where T : class, IStreamCompressor
+		{
+			builder.Services.AddScoped<IStreamCompressor, T>();
+			return builder;
+		}
+
+		public static IRpcBuilder WithReponseSerializer<T>(this IRpcBuilder builder) where T : class, IRpcResponseSerializer
+		{
+			builder.Services.AddScoped<IRpcResponseSerializer, T>();
+			return builder;
+		}
+
+		public static IRpcBuilder WithRequestMatcher<T>(this IRpcBuilder builder) where T : class, IRpcRequestMatcher
+		{
+			builder.Services.AddScoped<IRpcRequestMatcher, T>();
+			return builder;
+		}
+	}
+
+}

+ 11 - 0
JsonRPC4/Builder/RpcServicesMarker.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Builder
+{
+    public class RpcServicesMarker
+    {
+    }
+}

+ 28 - 0
JsonRPC4/Common/JsonRpcContants.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common
+{
+	public static class JsonRpcContants
+	{
+		public const string VersionPropertyName = "jsonrpc";
+
+		public const string MethodPropertyName = "method";
+
+		public const string ParamsPropertyName = "params";
+
+		public const string IdPropertyName = "id";
+
+		public const string ResultPropertyName = "result";
+
+		public const string ErrorPropertyName = "error";
+
+		public const string ErrorCodePropertyName = "code";
+
+		public const string ErrorMessagePropertyName = "message";
+
+		public const string ErrorDataPropertyName = "data";
+	}
+}

+ 66 - 0
JsonRPC4/Common/RpcError.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common
+{
+	public class RpcError
+	{
+		public int Code
+		{
+			get;
+		}
+
+		public string Message
+		{
+			get;
+		}
+
+		public object Data
+		{
+			get;
+		}
+
+		public Type DataType
+		{
+			get;
+		}
+
+		public RpcError(RpcErrorCode code, string message, object data = null)
+			: this((int)code, message, data)
+		{
+		}
+
+		public RpcError(int code, string message, object data = null)
+		{
+			if (string.IsNullOrWhiteSpace(message))
+			{
+				throw new ArgumentNullException("message");
+			}
+			Code = code;
+			Message = message;
+			Data = data;
+			DataType = data?.GetType();
+		}
+
+		public RpcException CreateException()
+		{
+			return new RpcException(Code, Message, null, Data);
+		}
+	}
+	public class RpcError<T> : RpcError
+	{
+		public new T Data => (T)base.Data;
+
+		public RpcError(RpcErrorCode code, string message, T data)
+			: base(code, message, data)
+		{
+		}
+
+		public RpcError(int code, string message, T data)
+			: base(code, message, data)
+		{
+		}
+	}
+}

+ 16 - 0
JsonRPC4/Common/RpcErrorCode.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common
+{
+	public enum RpcErrorCode
+	{
+		ParseError = -32700,
+		InvalidRequest = -32600,
+		MethodNotFound = -32601,
+		InvalidParams = -32602,
+		InternalError = -32603
+	}
+}

+ 43 - 0
JsonRPC4/Common/RpcException.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common
+{
+	// Token: 0x0200000D RID: 13
+	public class RpcException : Exception
+{
+	public int ErrorCode
+	{
+		get;
+	}
+
+	public object RpcData
+	{
+		get;
+	}
+
+	public RpcException(int errorCode, string message, Exception innerException = null, object data = null)
+		: base(message, innerException)
+	{
+		ErrorCode = errorCode;
+		RpcData = data;
+	}
+
+	public RpcException(RpcErrorCode errorCode, string message, Exception innerException = null, object data = null)
+		: this((int)errorCode, message, innerException, data)
+	{
+	}
+
+	public RpcError ToRpcError(bool includeServerErrors)
+	{
+		string text = Message;
+		if (includeServerErrors)
+		{
+			text = text + Environment.NewLine + "Exception: " + base.InnerException;
+		}
+		return new RpcError(ErrorCode, text, RpcData);
+	}
+}
+}

+ 167 - 0
JsonRPC4/Common/RpcId.cs

@@ -0,0 +1,167 @@
+using JsonRPC4.Common.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+namespace JsonRPC4.Common
+{
+
+	public struct RpcId : IEquatable<RpcId>
+	{
+		public bool HasValue
+		{
+			get;
+		}
+
+		public RpcIdType Type
+		{
+			get;
+		}
+
+		public object Value
+		{
+			get;
+		}
+
+		public long NumberValue
+		{
+			get
+			{
+				if (Type != RpcIdType.Number)
+				{
+					throw new InvalidOperationException("Cannot cast id to number.");
+				}
+				return (long)Value;
+			}
+		}
+
+		public string StringValue
+		{
+			get
+			{
+				if (Type != 0)
+				{
+					throw new InvalidOperationException("Cannot cast id to string.");
+				}
+				return (string)Value;
+			}
+		}
+
+		public RpcId(string id)
+		{
+			HasValue = (id != null);
+			Value = id;
+			Type = RpcIdType.String;
+		}
+
+		public RpcId(long id)
+		{
+			HasValue = true;
+			Value = id;
+			Type = RpcIdType.Number;
+		}
+
+		public static bool operator ==(RpcId x, RpcId y)
+		{
+			return x.Equals(y);
+		}
+
+		public static bool operator !=(RpcId x, RpcId y)
+		{
+			return !x.Equals(y);
+		}
+
+		public bool Equals(RpcId other)
+		{
+			if (HasValue && other.HasValue)
+			{
+				return true;
+			}
+			if (HasValue || other.HasValue)
+			{
+				return false;
+			}
+			if (Type != other.Type)
+			{
+				return false;
+			}
+			switch (Type)
+			{
+				case RpcIdType.Number:
+					return NumberValue == other.NumberValue;
+				case RpcIdType.String:
+					return StringValue == other.StringValue;
+				default:
+					throw new ArgumentOutOfRangeException("Type");
+			}
+		}
+
+		public override bool Equals(object obj)
+		{
+			if (obj is RpcId)
+			{
+				RpcId other = (RpcId)obj;
+				return Equals(other);
+			}
+			return false;
+		}
+
+		public override int GetHashCode()
+		{
+			if (!HasValue)
+			{
+				return 0;
+			}
+			return Value.GetHashCode();
+		}
+
+		public override string ToString()
+		{
+			if (!HasValue)
+			{
+				return string.Empty;
+			}
+			switch (Type)
+			{
+				case RpcIdType.Number:
+					return Value.ToString();
+				case RpcIdType.String:
+					return "'" + (string)Value + "'";
+				default:
+					throw new ArgumentOutOfRangeException("Type");
+			}
+		}
+
+		public static implicit operator RpcId(long id)
+		{
+			return new RpcId(id);
+		}
+
+		public static implicit operator RpcId(string id)
+		{
+			return new RpcId(id);
+		}
+
+		public static RpcId FromObject(object value)
+		{
+			if (value == null)
+			{
+				return default(RpcId);
+			}
+			if (value is RpcId)
+			{
+				return (RpcId)value;
+			}
+			string text = value as string;
+			if (text != null)
+			{
+				return new RpcId(text);
+			}
+			if (value.GetType().IsNumericType())
+			{
+				return new RpcId(Convert.ToInt64(value));
+			}
+			throw new RpcException(RpcErrorCode.InvalidRequest, "Id must be a string, a number or null.");
+		}
+	}
+}

+ 13 - 0
JsonRPC4/Common/RpcIdType.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common
+{
+	public enum RpcIdType
+	{
+		String,
+		Number
+	}
+}

+ 29 - 0
JsonRPC4/Common/Tools/DefaultStreamCompressor.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common.Tools
+{
+	public class DefaultStreamCompressor : IStreamCompressor
+	{
+		public bool TryGetCompressionStream(Stream uncompressedStream, string encoding, CompressionMode mode, out Stream compressedStream)
+		{
+			switch (encoding)
+			{
+				case "gzip":
+					compressedStream = new GZipStream(uncompressedStream, mode, leaveOpen: false);
+					return true;
+				case "deflate":
+					compressedStream = new DeflateStream(uncompressedStream, mode, leaveOpen: false);
+					return true;
+				default:
+					compressedStream = uncompressedStream;
+					return false;
+			}
+		}
+	}
+
+}

+ 14 - 0
JsonRPC4/Common/Tools/IStreamCompressor.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common.Tools
+{
+    public interface IStreamCompressor
+    {
+        bool TryGetCompressionStream(Stream uncompressedStream, string encoding, CompressionMode mode, out Stream compressedStream);
+    }
+}

+ 27 - 0
JsonRPC4/Common/Utilities/TypeExtensions.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Common.Utilities
+{
+    public static class TypeExtensions
+	{
+		public static bool IsNumericType(this Type type, bool includeInteger = true)
+		{
+			if (includeInteger)
+			{
+				if (!(type == typeof(long)) && !(type == typeof(int)) && !(type == typeof(short)) && !(type == typeof(float)) && !(type == typeof(double)))
+				{
+					return type == typeof(decimal);
+				}
+				return true;
+			}
+			if (!(type == typeof(float)) && !(type == typeof(double)))
+			{
+				return type == typeof(decimal);
+			}
+			return true;
+		}
+	}
+}

+ 13 - 0
JsonRPC4/Controllers/Item.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPCTest.Controllers
+{
+    public class Item
+    {
+        public string aaa { get; set; }
+        public string ccc { get; set; }
+    }
+}

+ 57 - 0
JsonRPC4/Controllers/WeatherForecastController.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using JsonRPC4.Router;
+using JsonRPC4.Router.Abstractions;
+using JsonRPCTest.Controllers;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+namespace JsonRPC4.Controllers
+{
+
+    [RpcRoute]
+    public class WeatherForecastController : RpcController
+    {
+        private static readonly string[] Summaries = new[]
+        {
+            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+        };
+
+        private readonly ILogger<WeatherForecastController> _logger;
+
+        public WeatherForecastController(ILogger<WeatherForecastController> logger)
+        {
+            _logger = logger;
+        }
+
+
+        //public Task<IRpcMethodResult> Get(Item item, JsonElement bbb)
+        //{
+        //    var rng = new Random();
+        //    var aps = Enumerable.Range(1, 5).Select(index => new WeatherForecast
+        //    {
+        //        Date = DateTime.Now.AddDays(index),
+        //        TemperatureC = rng.Next(-20, 55),
+        //        Summary = Summaries[rng.Next(Summaries.Length)]
+        //    })
+        //    .ToArray();
+        //    return Task.Run<IRpcMethodResult>(() => Ok(aps));
+        //}
+    
+        public Task<IRpcMethodResult> Get(string aaa, string ccc)
+        {
+            var rng = new Random();
+            var aps = Enumerable.Range(1, 5).Select(index => new WeatherForecast
+            {
+                Date = DateTime.Now.AddDays(index),
+                TemperatureC = rng.Next(-20, 55),
+                Summary = Summaries[rng.Next(Summaries.Length)]
+            })
+            .ToArray();
+            return Task.Run<IRpcMethodResult>(() => Ok(aps));
+        }
+    }
+}

+ 26 - 0
JsonRPC4/IRouteContext.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace JsonRPC4
+{
+	public interface IRouteContext
+	{
+		IServiceProvider RequestServices
+		{
+			get;
+		}
+
+		ClaimsPrincipal User
+		{
+			get;
+		}
+
+		IRpcMethodProvider MethodProvider
+		{
+			get;
+		}
+	}
+}

+ 14 - 0
JsonRPC4/IRpcMethodProvider.cs

@@ -0,0 +1,14 @@
+using JsonRPC4.Router;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4
+{
+    public interface IRpcMethodProvider
+    {
+        bool TryGetByPath(RpcPath path, out IReadOnlyList<MethodInfo> methods);
+    }
+}

+ 8 - 0
JsonRPC4/JsonRPC4.csproj

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

+ 26 - 0
JsonRPC4/Program.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace JsonRPC4
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                });
+    }
+}

+ 30 - 0
JsonRPC4/Properties/launchSettings.json

@@ -0,0 +1,30 @@
+{
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:49533",
+      "sslPort": 44305
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "JsonRPC4": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 14 - 0
JsonRPC4/Router/Abstractions/IRpcInvoker.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+	public interface IRpcInvoker
+	{
+		Task<RpcResponse> InvokeRequestAsync(RpcRequest request, IRouteContext routeContext, RpcPath path = null);
+
+		Task<List<RpcResponse>> InvokeBatchRequestAsync(IList<RpcRequest> requests, IRouteContext routeContext, RpcPath path = null);
+	}
+}

+ 13 - 0
JsonRPC4/Router/Abstractions/IRpcMethodResult.cs

@@ -0,0 +1,13 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+    public interface IRpcMethodResult
+    {
+        RpcResponse ToRpcResponse(RpcId id);
+    }
+}

+ 14 - 0
JsonRPC4/Router/Abstractions/IRpcParser.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+    public interface IRpcParser
+    {
+        ParsingResult ParseRequests(Stream jsonStream);
+    }
+
+}

+ 13 - 0
JsonRPC4/Router/Abstractions/IRpcRequestHandler.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+    public interface IRpcRequestHandler
+    {
+        Task<bool> HandleRequestAsync(RpcPath requestPath, Stream requestBody, IRouteContext routeContext, Stream responseBody);
+    }
+}

+ 14 - 0
JsonRPC4/Router/Abstractions/IRpcRequestMatcher.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+    public interface IRpcRequestMatcher
+    {
+        RpcMethodInfo GetMatchingMethod(RpcRequest request, IReadOnlyList<MethodInfo> methods);
+    }
+
+}

+ 15 - 0
JsonRPC4/Router/Abstractions/IRpcResponseSerializer.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+	public interface IRpcResponseSerializer
+	{
+		Task SerializeAsync(RpcResponse response, Stream stream);
+
+		Task SerializeBulkAsync(IEnumerable<RpcResponse> responses, Stream stream);
+	}
+}

+ 20 - 0
JsonRPC4/Router/Abstractions/RpcParserExtensions.cs

@@ -0,0 +1,20 @@
+using JsonRPC4.Router.Utilities;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+	public static class RpcParserExtensions
+	{
+		public static ParsingResult ParseRequests(this IRpcParser parser, string json)
+		{
+			using (MemoryStream jsonStream = StreamUtil.GetStreamFromUtf8String(json ?? string.Empty))
+			{
+				return parser.ParseRequests(jsonStream);
+			}
+		}
+	}
+}

+ 28 - 0
JsonRPC4/Router/Abstractions/RpcRequestHandlerExtensions.cs

@@ -0,0 +1,28 @@
+using JsonRPC4.Router.Utilities;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+	public static class RpcRequestHandlerExtensions
+	{
+		public static async Task<string> HandleRequestAsync(this IRpcRequestHandler handler, RpcPath requestPath, string requestJson, IRouteContext routeContext)
+		{
+			using (MemoryStream requestStream = StreamUtil.GetStreamFromUtf8String(requestJson))
+			{
+				using (MemoryStream responseStream = new MemoryStream())
+				{
+					if (!(await handler.HandleRequestAsync(requestPath, requestStream, routeContext, responseStream)))
+					{
+						return null;
+					}
+					responseStream.Position = 0L;
+					return await new StreamReader(responseStream).ReadToEndAsync();
+				}
+			}
+		}
+	}
+}

+ 35 - 0
JsonRPC4/Router/Abstractions/RpcResponseSerializerExtensions.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Abstractions
+{
+	public static class RpcResponseSerializerExtensions
+	{
+		public static async Task<string> SerializeAsync(this IRpcResponseSerializer serializer, RpcResponse response)
+		{
+			using (MemoryStream stream = new MemoryStream())
+			{
+				await serializer.SerializeAsync(response, stream);
+				return await GetStringAsync(stream);
+			}
+		}
+
+		public static async Task<string> SerializeBulkAsync(this IRpcResponseSerializer serializer, IEnumerable<RpcResponse> responses)
+		{
+			using (MemoryStream stream = new MemoryStream())
+			{
+				await serializer.SerializeBulkAsync(responses, stream);
+				return await GetStringAsync(stream);
+			}
+		}
+
+		private static Task<string> GetStringAsync(MemoryStream stream)
+		{
+			stream.Position = 0L;
+			return new StreamReader(stream).ReadToEndAsync();
+		}
+	}
+}

+ 473 - 0
JsonRPC4/Router/Defaults/DefaultRequestMatcher.cs

@@ -0,0 +1,473 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Utilities;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Buffers;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class DefaultRequestMatcher : IRpcRequestMatcher
+	{
+		private class CompiledMethodInfo
+		{
+			public MethodInfo MethodInfo
+			{
+				get;
+			}
+
+			public CompiledParameterInfo[] Parameters
+			{
+				get;
+			}
+
+			public CompiledMethodInfo(MethodInfo methodInfo, CompiledParameterInfo[] parameters)
+			{
+				MethodInfo = methodInfo;
+				Parameters = parameters;
+			}
+		}
+
+		private class CompiledParameterInfo
+		{
+			public string Name
+			{
+				get;
+			}
+
+			public RpcParameterType Type
+			{
+				get;
+			}
+
+			public Type RawType
+			{
+				get;
+			}
+
+			public bool IsOptional
+			{
+				get;
+			}
+
+			public CompiledParameterInfo(string name, RpcParameterType type, Type rawType, bool isOptional)
+			{
+				Name = name;
+				Type = type;
+				RawType = rawType;
+				IsOptional = isOptional;
+			}
+		}
+
+		private static ConcurrentDictionary<MethodInfo, CompiledMethodInfo> compiledMethodCache
+		{
+			get;
+		} = new ConcurrentDictionary<MethodInfo, CompiledMethodInfo>();
+
+
+		private static ConcurrentDictionary<string, RpcMethodInfo[]> requestToMethodCache
+		{
+			get;
+		} = new ConcurrentDictionary<string, RpcMethodInfo[]>();
+
+
+		private ILogger<DefaultRequestMatcher> logger
+		{
+			get;
+		}
+
+		private IOptions<RpcServerConfiguration> serverConfig
+		{
+			get;
+		}
+
+		public DefaultRequestMatcher(ILogger<DefaultRequestMatcher> logger, IOptions<RpcServerConfiguration> serverConfig)
+		{
+			this.logger = logger;
+			this.serverConfig = serverConfig;
+		}
+
+		public RpcMethodInfo GetMatchingMethod(RpcRequest request, IReadOnlyList<MethodInfo> methods)
+		{
+			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
+			if (request == null)
+			{
+				throw new ArgumentNullException("request");
+			}
+			logger.AttemptingToMatchMethod(request.Method);
+			CompiledMethodInfo[] array = ArrayPool<CompiledMethodInfo>.Shared.Rent(methods.Count);
+			Span<RpcMethodInfo> val;
+			try
+			{
+				FillCompiledMethodInfos(methods, array);
+				val = FilterAndBuildMethodInfoByRequest(MemoryExtensions.AsSpan<CompiledMethodInfo>(array, 0, methods.Count), request);
+
+			}
+			finally
+			{
+				ArrayPool<CompiledMethodInfo>.Shared.Return(array, true);
+			}
+			if (val.Length  == 1)
+			{
+				logger.RequestMatchedMethod();
+				return val[0];
+			}
+			string message;
+			if (val.Length > 1)
+			{
+				List<string> list = new List<string>();
+				Span<RpcMethodInfo> val2 = val;
+				for (int i = 0; i < val2.Length; i++)
+				{
+					RpcMethodInfo rpcMethodInfo = val2[i];
+					List<string> list2 = new List<string>();
+					ParameterInfo[] parameters = rpcMethodInfo.Method.GetParameters();
+					foreach (ParameterInfo parameterInfo in parameters)
+					{
+						string text = parameterInfo.Name + ": " + parameterInfo.ParameterType.Name;
+						if (parameterInfo.IsOptional)
+						{
+							text += "(Optional)";
+						}
+						list2.Add(text);
+					}
+					string text2 = string.Join(", ", list2);
+					list.Add("{Name: '" + rpcMethodInfo.Method.Name + "', Parameters: [" + text2 + "]}");
+				}
+				message = "More than one method matched the rpc request. Unable to invoke due to ambiguity. Methods that matched the same name: " + string.Join(", ", list);
+			}
+			else
+			{
+				logger.MethodsInRoute(methods);
+				message = "No methods matched request.";
+			}
+			throw new RpcException(RpcErrorCode.MethodNotFound, message);
+		}
+
+		private void FillCompiledMethodInfos(IReadOnlyList<MethodInfo> methods, CompiledMethodInfo[] compiledMethods)
+		{
+			for (int i = 0; i < methods.Count; i++)
+			{
+				MethodInfo methodInfo = methods[i];
+				if (!compiledMethodCache.TryGetValue(methodInfo, out CompiledMethodInfo value))
+				{
+					CompiledParameterInfo[] parameters = methodInfo.GetParameters().Select(ExtractParam).ToArray();
+					value = new CompiledMethodInfo(methodInfo, parameters);
+				}
+				compiledMethods[i] = value;
+			}
+			CompiledParameterInfo ExtractParam(ParameterInfo parameterInfo)
+			{
+				Type type = parameterInfo.ParameterType;
+				if (type.IsGenericType)
+				{
+					Type underlyingType = Nullable.GetUnderlyingType(type);
+					if (underlyingType != null)
+					{
+						type = underlyingType;
+					}
+				}
+				return new CompiledParameterInfo(type: (type == typeof(short) || type == typeof(ushort) || type == typeof(int) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong) || type == typeof(float) || type == typeof(double) || type == typeof(decimal)) ? RpcParameterType.Number : ((!(type == typeof(string))) ? RpcParameterType.Object : RpcParameterType.String), name: parameterInfo.Name, rawType: parameterInfo.ParameterType, isOptional: parameterInfo.IsOptional);
+			}
+		}
+
+		private   RpcMethodInfo[] FilterAndBuildMethodInfoByRequest(ReadOnlySpan<CompiledMethodInfo> methods, RpcRequest request)
+		{
+			int num = 0;
+			int num2 = 200;
+			int num3 = request.Method.Length;
+			if (request.Parameters != null)
+			{
+				num3 += 3 + num2;
+			}
+			char[] array = ArrayPool<char>.Shared.Rent(num3);
+			RpcMethodInfo[] result;
+			try
+			{
+				for (int i = 0; i < request.Method.Length; i++)
+				{
+					array[num++] = request.Method[i];
+				}
+				if (request.Parameters != null)
+				{
+					array[num++] = ' ';
+					array[num++] = (request.Parameters.IsDictionary ? 'd' : 'a');
+					array[num++] = ' ';
+					if (request.Parameters.IsDictionary)
+					{
+						using (Dictionary<string, IRpcParameter>.Enumerator enumerator = request.Parameters.AsDictionary.GetEnumerator())
+						{
+							while (enumerator.MoveNext())
+							{
+								KeyValuePair<string, IRpcParameter> keyValuePair = enumerator.Current;
+								if (num + keyValuePair.Key.Length + 1 >= keyValuePair.Key.Length)
+								{
+									ArrayPool<char>.Shared.Return(array, false);
+									array = ArrayPool<char>.Shared.Rent(array.Length + 30);
+								}
+								array[num++] = ' ';
+								for (int j = 0; j < keyValuePair.Key.Length; j++)
+								{
+									array[num++] = keyValuePair.Key[j];
+								}
+							}
+							goto IL_1E3;
+						}
+					}
+					List<IRpcParameter> asList = request.Parameters.AsList;
+					for (int k = 0; k < asList.Count; k++)
+					{
+						char c;
+						switch (asList[k].Type)
+						{
+							case RpcParameterType.Null:
+								c = '-';
+								break;
+							case RpcParameterType.Number:
+								c = 'n';
+								break;
+							case RpcParameterType.String:
+								c = 's';
+								break;
+							case RpcParameterType.Object:
+								c = 'o';
+								break;
+							default:
+								throw new InvalidOperationException(string.Format("Unimplemented parameter type '{0}'", asList[k].Type));
+						}
+						array[num++] = c;
+					}
+				}
+			IL_1E3:
+				string text = new string(array, 0, num);
+				RpcMethodInfo[] array2;
+				if (DefaultRequestMatcher.requestToMethodCache.TryGetValue(text, out array2))
+				{
+					result = array2;
+				}
+				else
+				{
+					DefaultRequestMatcher.CompiledMethodInfo[] array3 = ArrayPool<DefaultRequestMatcher.CompiledMethodInfo>.Shared.Rent(methods.Length);
+					try
+					{
+						int num4 = 0;
+						for (int l = 0; l < methods.Length; l++)
+						{
+							DefaultRequestMatcher.CompiledMethodInfo compiledMethodInfo = methods[l];
+							if (RpcUtil.NamesMatch(MemoryExtensions.AsSpan(compiledMethodInfo.MethodInfo.Name), MemoryExtensions.AsSpan(request.Method)))
+							{
+								array3[num4++] = compiledMethodInfo;
+							}
+						}
+						Span<RpcMethodInfo> span;
+						if (num4 < 1)
+						{
+							span = Span<RpcMethodInfo>.Empty;
+						}
+						else
+						{
+							RpcMethodInfo[] array4 = ArrayPool<RpcMethodInfo>.Shared.Rent(num4);
+							try
+							{
+								int num5 = 0;
+								for (int m = 0; m < num4; m++)
+								{
+									DefaultRequestMatcher.CompiledMethodInfo method = array3[m];
+									ValueTuple<bool, RpcMethodInfo> valueTuple = this.HasParameterSignature(method, request);
+									bool item = valueTuple.Item1;
+									RpcMethodInfo item2 = valueTuple.Item2;
+									if (item)
+									{
+										array4[num5++] = item2;
+									}
+								}
+								if (num5 <= 1)
+								{
+									span = MemoryExtensions.AsSpan<RpcMethodInfo>(array4, 0, num5);
+								}
+								else
+								{
+									RpcMethodInfo[] array5 = ArrayPool<RpcMethodInfo>.Shared.Rent(num5);
+									try
+									{
+										int num6 = 0;
+										for (int n = 0; n < num5; n++)
+										{
+											bool flag = true;
+											RpcMethodInfo rpcMethodInfo = array4[n];
+											ParameterInfo[] parameters = rpcMethodInfo.Method.GetParameters();
+											if (rpcMethodInfo.Parameters.Length == parameters.Length)
+											{
+												for (int num7 = 0; num7 < rpcMethodInfo.Parameters.Length; num7++)
+												{
+													object value = rpcMethodInfo.Parameters[num7];
+													ParameterInfo parameterInfo = parameters[num7];
+													if (!RpcUtil.TypesMatch(value, parameterInfo.ParameterType))
+													{
+														flag = false;
+														break;
+													}
+												}
+											}
+											else
+											{
+												flag = false;
+											}
+											if (flag)
+											{
+												array5[num6++] = array4[n];
+											}
+										}
+										RpcMethodInfo[] array7;
+										int num9;
+										if (num6 <= 0)
+										{
+											RpcMethodInfo[] array6 = array4;
+											int num8 = num5;
+											array7 = array6;
+											num9 = num8;
+										}
+										else
+										{
+											RpcMethodInfo[] array8 = array5;
+											int num8 = num6;
+											array7 = array8;
+											num9 = num8;
+										}
+										if (num9 <= 1)
+										{
+											span = MemoryExtensions.AsSpan<RpcMethodInfo>(array4, 0, num9);
+										}
+										else
+										{
+											RpcMethodInfo[] array9 = ArrayPool<RpcMethodInfo>.Shared.Rent(num9);
+											try
+											{
+												int num10 = 0;
+												for (int num11 = 0; num11 < num9; num11++)
+												{
+													RpcMethodInfo rpcMethodInfo2 = array7[num11];
+													if (string.Equals(rpcMethodInfo2.Method.Name, request.Method, StringComparison.Ordinal))
+													{
+														array9[num10++] = rpcMethodInfo2;
+													}
+												}
+												span = MemoryExtensions.AsSpan<RpcMethodInfo>(array9, 0, num10);
+											}
+											finally
+											{
+												ArrayPool<RpcMethodInfo>.Shared.Return(array9, false);
+											}
+										}
+									}
+									finally
+									{
+										ArrayPool<RpcMethodInfo>.Shared.Return(array5, false);
+									}
+								}
+							}
+							finally
+							{
+								ArrayPool<RpcMethodInfo>.Shared.Return(array4, false);
+							}
+						}
+						RpcMethodInfo[] array10 = span.ToArray();
+						DefaultRequestMatcher.requestToMethodCache.TryAdd(text, array10);
+						result = array10;
+					}
+					finally
+					{
+						ArrayPool<DefaultRequestMatcher.CompiledMethodInfo>.Shared.Return(array3, false);
+					}
+				}
+			}
+			finally
+			{
+				ArrayPool<char>.Shared.Return(array, false);
+			}
+			return result;
+		}
+
+		private (bool Matches, RpcMethodInfo MethodInfo) HasParameterSignature(CompiledMethodInfo method, RpcRequest rpcRequest)
+		{
+			IList<IRpcParameter> parameterList;
+			if (rpcRequest.Parameters == null)
+			{
+				parameterList = new IRpcParameter[0];
+			}
+			else if (rpcRequest.Parameters.IsDictionary)
+			{
+				Dictionary<string, IRpcParameter> asDictionary = rpcRequest.Parameters.AsDictionary;
+				if (!TryParseParameterList(method, asDictionary, out parameterList))
+				{
+					return (false, null);
+				}
+			}
+			else
+			{
+				parameterList = rpcRequest.Parameters.AsList;
+			}
+			if (parameterList.Count() > method.Parameters.Length)
+			{
+				return (false, null);
+			}
+			for (int i = 0; i < parameterList.Count(); i++)
+			{
+				CompiledParameterInfo compiledParameterInfo = method.Parameters[i];
+				IRpcParameter rpcParameter = parameterList[i];
+				if (rpcParameter.Type != compiledParameterInfo.Type && compiledParameterInfo.Type != RpcParameterType.Object && (rpcParameter.Type != 0 || !compiledParameterInfo.RawType.IsNullableType()))
+				{
+					return (false, null);
+				}
+			}
+			object[] array = new object[method.Parameters.Length];
+			for (int j = 0; j < parameterList.Count(); j++)
+			{
+				CompiledParameterInfo compiledParameterInfo2 = method.Parameters[j];
+				if (!parameterList[j].TryGetValue(compiledParameterInfo2.RawType, out object value))
+				{
+					return (false, null);
+				}
+				array[j] = value;
+			}
+			RpcMethodInfo item = new RpcMethodInfo(method.MethodInfo, array);
+			return (true, item);
+		}
+
+		private bool TryParseParameterList(CompiledMethodInfo method, Dictionary<string, IRpcParameter> requestParameters, out IList<IRpcParameter> parameterList)
+		{
+			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
+			parameterList = new IRpcParameter[method.Parameters.Count()];
+			for (int i = 0; i < method.Parameters.Length; i++)
+			{
+				CompiledParameterInfo compiledParameterInfo = method.Parameters[i];
+				foreach (KeyValuePair<string, IRpcParameter> requestParameter in requestParameters)
+				{
+					if (RpcUtil.NamesMatch(MemoryExtensions.AsSpan(compiledParameterInfo.Name), MemoryExtensions.AsSpan(requestParameter.Key)))
+					{
+						parameterList[i] = requestParameter.Value;
+					}
+				}
+				if (!compiledParameterInfo.IsOptional)
+				{
+					parameterList = null;
+					return false;
+				}
+			}
+			return true;
+		}
+	}
+
+}

+ 40 - 0
JsonRPC4/Router/Defaults/DefaultRouteContext.cs

@@ -0,0 +1,40 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+
+	public class DefaultRouteContext : IRouteContext
+	{
+		public IServiceProvider RequestServices
+		{
+			get;
+		}
+
+		public ClaimsPrincipal User
+		{
+			get;
+		}
+
+		public IRpcMethodProvider MethodProvider
+		{
+			get;
+		}
+
+		public DefaultRouteContext(IServiceProvider serviceProvider, ClaimsPrincipal user, IRpcMethodProvider methodProvider)
+		{
+			RequestServices = serviceProvider;
+			User = user;
+			MethodProvider = methodProvider;
+		}
+
+		public static IRouteContext FromHttpContext(HttpContext httpContext, IRpcMethodProvider methodProvider)
+		{
+			return new DefaultRouteContext(httpContext.RequestServices, httpContext.User, methodProvider);
+		}
+	}
+}

+ 272 - 0
JsonRPC4/Router/Defaults/DefaultRpcInvoker.cs

@@ -0,0 +1,272 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Utilities;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class DefaultRpcInvoker : IRpcInvoker
+	{
+		private ILogger<DefaultRpcInvoker> logger
+		{
+			get;
+		}
+
+		private IAuthorizationService authorizationService
+		{
+			get;
+		}
+
+		private IAuthorizationPolicyProvider policyProvider
+		{
+			get;
+		}
+
+		private IOptions<RpcServerConfiguration> serverConfig
+		{
+			get;
+		}
+
+		private IRpcRequestMatcher rpcRequestMatcher
+		{
+			get;
+		}
+
+		private ConcurrentDictionary<Type, ObjectFactory> objectFactoryCache
+		{
+			get;
+		} = new ConcurrentDictionary<Type, ObjectFactory>();
+
+
+		private ConcurrentDictionary<Type, (List<IAuthorizeData>, bool)> classAttributeCache
+		{
+			get;
+		} = new ConcurrentDictionary<Type, (List<IAuthorizeData>, bool)>();
+
+
+		private ConcurrentDictionary<RpcMethodInfo, (List<IAuthorizeData>, bool)> methodAttributeCache
+		{
+			get;
+		} = new ConcurrentDictionary<RpcMethodInfo, (List<IAuthorizeData>, bool)>();
+
+
+		public DefaultRpcInvoker(IAuthorizationService authorizationService, IAuthorizationPolicyProvider policyProvider, ILogger<DefaultRpcInvoker> logger, IOptions<RpcServerConfiguration> serverConfig, IRpcRequestMatcher rpcRequestMatcher)
+		{
+			this.authorizationService = authorizationService;
+			this.policyProvider = policyProvider;
+			this.logger = logger;
+			this.serverConfig = serverConfig;
+			this.rpcRequestMatcher = rpcRequestMatcher;
+		}
+
+		public async Task<List<RpcResponse>> InvokeBatchRequestAsync(IList<RpcRequest> requests, IRouteContext routeContext, RpcPath path = null)
+		{
+			logger.InvokingBatchRequests(requests.Count);
+			List<Task<RpcResponse>> invokingTasks = new List<Task<RpcResponse>>();
+			foreach (RpcRequest request in requests)
+			{
+				Task<RpcResponse> item = InvokeRequestAsync(request, routeContext, path);
+				if (request.Id.HasValue)
+				{
+					invokingTasks.Add(item);
+				}
+			}
+			await Task.WhenAll(invokingTasks.ToArray());
+			List<RpcResponse> result = (from t in invokingTasks
+										select t.Result into r
+										where r != null
+										select r).ToList();
+			logger.BatchRequestsComplete();
+			return result;
+		}
+
+		public async Task<RpcResponse> InvokeRequestAsync(RpcRequest request, IRouteContext routeContext, RpcPath path = null)
+		{
+			if (request == null)
+			{
+				throw new ArgumentNullException("request");
+			}
+			logger.InvokingRequest(request.Id);
+			RpcResponse result;
+			try
+			{
+				if (!routeContext.MethodProvider.TryGetByPath(path, out IReadOnlyList<MethodInfo> methods))
+				{
+					throw new RpcException(RpcErrorCode.MethodNotFound, $"No methods found with the path: {path}");
+				}
+				RpcMethodInfo rpcMethod = rpcRequestMatcher.GetMatchingMethod(request, methods);
+				if (await IsAuthorizedAsync(rpcMethod, routeContext))
+				{
+					logger.InvokeMethod(request.Method);
+					object obj = await InvokeAsync(rpcMethod, path, routeContext.RequestServices);
+					logger.InvokeMethodComplete(request.Method);
+					IRpcMethodResult rpcMethodResult = obj as IRpcMethodResult;
+					result = ((rpcMethodResult == null) ? new RpcResponse(request.Id, obj) : rpcMethodResult.ToRpcResponse(request.Id));
+				}
+				else
+				{
+					RpcError error = new RpcError(RpcErrorCode.InvalidRequest, "Unauthorized");
+					result = new RpcResponse(request.Id, error);
+				}
+			}
+			catch (Exception ex)
+			{
+				logger.LogException(ex, "An Rpc error occurred while trying to invoke request.");
+				RpcException ex2 = ex as RpcException;
+				result = new RpcResponse(error: (ex2 == null) ? new RpcError(RpcErrorCode.InternalError, "An Rpc error occurred while trying to invoke request.", ex) : ex2.ToRpcError(serverConfig.Value.ShowServerExceptions), id: request.Id);
+			}
+			if (request.Id.HasValue)
+			{
+				logger.FinishedRequest(request.Id.ToString());
+				return result;
+			}
+			logger.FinishedRequestNoId();
+			return null;
+		}
+
+		private async Task<bool> IsAuthorizedAsync(RpcMethodInfo methodInfo, IRouteContext routeContext)
+		{
+			(List<IAuthorizeData>, bool) orAdd = classAttributeCache.GetOrAdd(methodInfo.Method.DeclaringType, GetClassAttributeInfo);
+			List<IAuthorizeData> item = orAdd.Item1;
+			bool item2 = orAdd.Item2;
+			(List<IAuthorizeData>, bool) orAdd2 = methodAttributeCache.GetOrAdd(methodInfo, GetMethodAttributeInfo);
+			List<IAuthorizeData> authorizeDataListMethod = orAdd2.Item1;
+			bool item3 = orAdd2.Item2;
+			if (item.Any() || authorizeDataListMethod.Any())
+			{
+				if (item2 || item3)
+				{
+					logger.SkippingAuth();
+				}
+				else
+				{
+					logger.RunningAuth();
+					AuthorizationResult authorizationResult = await CheckAuthorize(item, routeContext);
+					if (authorizationResult.Succeeded)
+					{
+						authorizationResult = await CheckAuthorize(authorizeDataListMethod, routeContext);
+					}
+					if (!authorizationResult.Succeeded)
+					{
+						logger.AuthFailed();
+						return false;
+					}
+					logger.AuthSuccessful();
+				}
+			}
+			else
+			{
+				logger.NoConfiguredAuth();
+			}
+			return true;
+			(List<IAuthorizeData> Data, bool allowAnonymous) GetAttributeInfo(IEnumerable<Attribute> attributes)
+			{
+				bool flag = false;
+				List<IAuthorizeData> list = new List<IAuthorizeData>(10);
+				foreach (Attribute attribute in attributes)
+				{
+					IAuthorizeData authorizeData = attribute as IAuthorizeData;
+					if (authorizeData != null)
+					{
+						list.Add(authorizeData);
+					}
+					if (!flag && attribute is IAllowAnonymous)
+					{
+						flag = true;
+					}
+				}
+				return (list, flag);
+			}
+			(List<IAuthorizeData> Data, bool allowAnonymous) GetClassAttributeInfo(Type type)
+			{
+				return GetAttributeInfo(type.GetCustomAttributes());
+			}
+			(List<IAuthorizeData> Data, bool allowAnonymous) GetMethodAttributeInfo(RpcMethodInfo info)
+			{
+				return GetAttributeInfo(info.Method.GetCustomAttributes());
+			}
+		}
+
+		private async Task<AuthorizationResult> CheckAuthorize(List<IAuthorizeData> authorizeDataList, IRouteContext routeContext)
+		{
+			if (!authorizeDataList.Any())
+			{
+				return AuthorizationResult.Success();
+			}
+			AuthorizationPolicy policy = await AuthorizationPolicy.CombineAsync(policyProvider, authorizeDataList);
+			return await authorizationService.AuthorizeAsync(routeContext.User, policy);
+		}
+
+		private async Task<object> InvokeAsync(RpcMethodInfo methodInfo, RpcPath path, IServiceProvider serviceProvider)
+		{
+			object obj = null;
+			if (serviceProvider != null)
+			{
+				obj = objectFactoryCache.GetOrAdd(methodInfo.Method.DeclaringType, (Type t) => ActivatorUtilities.CreateFactory(t, new Type[0]))(serviceProvider, null);
+			}
+			if (obj == null)
+			{
+				obj = Activator.CreateInstance(methodInfo.Method.DeclaringType);
+			}
+			try
+			{
+				return await HandleAsyncResponses(methodInfo.Method.Invoke(obj, methodInfo.Parameters));
+			}
+			catch (TargetInvocationException ex)
+			{
+				RpcRouteInfo routeInfo = new RpcRouteInfo(methodInfo, path, serviceProvider);
+				RpcErrorFilterAttribute customAttribute = methodInfo.Method.DeclaringType.GetTypeInfo().GetCustomAttribute<RpcErrorFilterAttribute>();
+				if (customAttribute != null)
+				{
+					OnExceptionResult onExceptionResult = customAttribute.OnException(routeInfo, ex.InnerException);
+					if (!onExceptionResult.ThrowException)
+					{
+						return onExceptionResult.ResponseObject;
+					}
+					Exception ex2 = onExceptionResult.ResponseObject as Exception;
+					if (ex2 != null)
+					{
+						throw ex2;
+					}
+				}
+				throw new RpcException(RpcErrorCode.InternalError, "Exception occurred from target method execution.", ex);
+			}
+			catch (Exception innerException)
+			{
+				throw new RpcException(RpcErrorCode.InvalidParams, "Exception from attempting to invoke method. Possibly invalid parameters for method.", innerException);
+			}
+		}
+
+		private static async Task<object> HandleAsyncResponses(object returnObj)
+		{
+			Task task = returnObj as Task;
+			if (task == null)
+			{
+				return returnObj;
+			}
+			try
+			{
+				await task;
+			}
+			catch (Exception inner)
+			{
+				throw new TargetInvocationException(inner);
+			}
+			PropertyInfo property = task.GetType().GetProperty("Result");
+			if (property != null)
+			{
+				return property.GetValue(returnObj);
+			}
+			return null;
+		}
+	}
+}

+ 283 - 0
JsonRPC4/Router/Defaults/DefaultRpcParser.cs

@@ -0,0 +1,283 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Utilities;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class DefaultRpcParser : IRpcParser
+	{
+		private ILogger<DefaultRpcParser> logger
+		{
+			get;
+		}
+
+		private IOptions<RpcServerConfiguration> serverConfig
+		{
+			get;
+		}
+
+		public DefaultRpcParser(ILogger<DefaultRpcParser> logger, IOptions<RpcServerConfiguration> serverConfig)
+		{
+			this.logger = logger;
+			this.serverConfig = serverConfig;
+		}
+
+		public ParsingResult ParseRequests(Stream jsonStream)
+		{
+			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
+			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
+			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
+			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
+			//IL_009f: Invalid comparison between Unknown and I4
+			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
+			//IL_00a4: Invalid comparison between Unknown and I4
+			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
+			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
+			//IL_010a: Invalid comparison between Unknown and I4
+			logger.ParsingRequests();
+			List<RpcRequestParseResult> list = null;
+			if (jsonStream == null || jsonStream.Length < 1)
+			{
+				throw new RpcException(RpcErrorCode.InvalidRequest, "Json request was empty");
+			}
+			bool isBulkRequest = false;
+			try
+			{
+				if (jsonStream.Length > int.MaxValue)
+				{
+					throw new RpcException(RpcErrorCode.ParseError, "Json body is too large to parse.");
+				}
+				byte[] array = ArrayPool<byte>.Shared.Rent((int)jsonStream.Length);
+				try
+				{
+					jsonStream.Read(array, 0, (int)jsonStream.Length);
+			 
+					Utf8JsonReader jsonReader = new  Utf8JsonReader(array, default(JsonReaderOptions));
+				 
+					if (jsonReader.Read())
+					{
+						JsonTokenType tokenType = jsonReader.TokenType;
+						if ( tokenType != JsonTokenType.StartObject)
+						{
+							if ( tokenType != JsonTokenType.StartArray)
+							{
+								throw new RpcException(RpcErrorCode.InvalidRequest, "Json request was invalid");
+							}
+							isBulkRequest = true;
+							jsonReader.Read();
+							list = new List<RpcRequestParseResult>();
+							while (jsonReader.TokenType !=JsonTokenType.EndObject)
+							{
+								RpcRequestParseResult item = ParseResult(ref jsonReader, array);
+								list.Add(item);
+								jsonReader.Read();
+							}
+						}
+						else
+						{
+							jsonReader.Read();
+							RpcRequestParseResult item2 = ParseResult(ref jsonReader, array);
+							list = new List<RpcRequestParseResult>
+							{
+								item2
+							};
+						}
+					}
+				}
+				finally
+				{
+					ArrayPool<byte>.Shared.Return(array, false);
+				}
+			}
+			catch (Exception ex) when (!(ex is RpcException))
+			{
+				string message = "Unable to parse json request into an rpc format.";
+				logger.LogException(ex, message);
+				throw new RpcException(RpcErrorCode.InvalidRequest, message, ex);
+			}
+			if (list == null || !list.Any())
+			{
+				throw new RpcException(RpcErrorCode.InvalidRequest, "No rpc json requests found");
+			}
+			logger.ParsedRequests(list.Count);
+			HashSet<RpcId> hashSet = new HashSet<RpcId>();
+			foreach (RpcRequestParseResult item3 in list.Where((RpcRequestParseResult r) => r.Id.HasValue))
+			{
+				if (!hashSet.Add(item3.Id))
+				{
+					throw new RpcException(RpcErrorCode.InvalidRequest, "Duplicate ids in batch requests are not allowed");
+				}
+			}
+			return ParsingResult.FromResults(list, isBulkRequest);
+		}
+
+		private RpcRequestParseResult ParseResult(ref Utf8JsonReader jsonReader, Memory<byte> bytes)
+		{
+			 
+			RpcId id = default(RpcId);
+			string text = null;
+			RpcParameters parameters = null;
+			string text2 = null;
+			try
+			{
+				if (jsonReader.TokenType  == JsonTokenType.StartObject)
+				{
+					jsonReader.Read();
+				}
+				long id2 = default;
+				while (jsonReader.TokenType != JsonTokenType.EndObject)
+				{
+					string @string = jsonReader.GetString();
+					jsonReader.Read();
+					switch (@string)
+					{
+						case "id":
+							{
+								JsonTokenType tokenType = jsonReader.TokenType;
+								if (tokenType != JsonTokenType.String)
+								{
+									if ((int)tokenType != 8)
+									{
+										RpcError error = new RpcError(RpcErrorCode.ParseError, "Unable to parse rpc id as a string or an integer");
+										return RpcRequestParseResult.Fail(id, error);
+									}
+									 
+									if (!(jsonReader).TryGetInt64(out id2))
+									{
+										RpcError error2 = new RpcError(RpcErrorCode.ParseError, "Unable to parse rpc id as an integer");
+										return RpcRequestParseResult.Fail(id, error2);
+									}
+									id = new RpcId(id2);
+								}
+								else
+								{
+									id = new RpcId(jsonReader.GetString());
+								}
+								break;
+							}
+						case "jsonrpc":
+							text2 = jsonReader.GetString();
+							break;
+						case "method":
+							text = jsonReader.GetString();
+							break;
+						case "params":
+							{
+								JsonTokenType tokenType = jsonReader.TokenType;
+								RpcParameters rpcParameters;
+								if ((int)tokenType != 1)
+								{
+									if ((int)tokenType != 3)
+									{
+										return RpcRequestParseResult.Fail(id, new RpcError(RpcErrorCode.InvalidRequest, "The request parameter format is invalid."));
+									}
+									jsonReader.Read();
+									List<IRpcParameter> list = new List<IRpcParameter>();
+									while (jsonReader.TokenType != JsonTokenType.EndArray)
+									{
+										IRpcParameter parameter = GetParameter(ref jsonReader, bytes);
+										list.Add(parameter);
+									}
+									rpcParameters = new RpcParameters(list);
+								}
+								else
+								{
+									jsonReader.Read();
+									Dictionary<string, IRpcParameter> dictionary = new Dictionary<string, IRpcParameter>();
+									while (jsonReader.TokenType != JsonTokenType.EndObject)
+									{
+										string string2 = jsonReader.GetString();
+										jsonReader.Read();
+										IRpcParameter parameter2 = GetParameter(ref jsonReader, bytes);
+										dictionary.Add(string2, parameter2);
+									}
+									rpcParameters = new RpcParameters(dictionary);
+								}
+								parameters = rpcParameters;
+								break;
+							}
+					}
+					jsonReader.Read();
+				}
+				if (string.IsNullOrWhiteSpace(text))
+				{
+					return RpcRequestParseResult.Fail(id, new RpcError(RpcErrorCode.InvalidRequest, "The request method is required."));
+				}
+				if (string.IsNullOrWhiteSpace(text2))
+				{
+					return RpcRequestParseResult.Fail(id, new RpcError(RpcErrorCode.InvalidRequest, "The jsonrpc version must be specified."));
+				}
+				if (!string.Equals(text2, "2.0", StringComparison.OrdinalIgnoreCase))
+				{
+					return RpcRequestParseResult.Fail(id, new RpcError(RpcErrorCode.InvalidRequest, "The jsonrpc version '" + text2 + "' is not supported. Supported versions: '2.0'"));
+				}
+				return RpcRequestParseResult.Success(id, text, parameters);
+			}
+			catch (Exception ex)
+			{
+				RpcException ex2 = ex as RpcException;
+				RpcError error3 = (ex2 == null) ? new RpcError(RpcErrorCode.ParseError, "Failed to parse request.", ex) : ex2.ToRpcError(serverConfig.Value.ShowServerExceptions);
+				return RpcRequestParseResult.Fail(id, error3);
+			}
+		}
+
+		private JsonBytesRpcParameter GetParameter(ref Utf8JsonReader jsonReader, Memory<byte> bytes)
+		{
+			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
+			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0013: Invalid comparison between Unknown and I4
+			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0032: Expected I4, but got Unknown
+			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0059: Invalid comparison between Unknown and I4
+			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
+			int num = (int)jsonReader.TokenStartIndex;
+			JsonTokenType tokenType = jsonReader.TokenType;
+			RpcParameterType type;
+			if ((int)tokenType != 1)
+			{
+				switch (tokenType )
+				{
+					case JsonTokenType.Number:
+						type = RpcParameterType.Number;
+						break;
+					case JsonTokenType.Null:
+						type = RpcParameterType.Null;
+						break;
+					case JsonTokenType.String:
+						type = RpcParameterType.String;
+						break;
+					default:
+						throw new RpcException(RpcErrorCode.ParseError, "Invalid json");
+				}
+			}
+			else
+			{
+				type = RpcParameterType.Object;
+				int currentDepth = jsonReader.CurrentDepth; 
+				while (jsonReader.TokenType != JsonTokenType.EndObject || jsonReader.CurrentDepth != currentDepth)
+				{
+					jsonReader.Read();
+				}
+			}
+			int num2 = (int)jsonReader.BytesConsumed - num;
+			jsonReader.Read();
+			return new JsonBytesRpcParameter(type, bytes.Slice(num, num2), serverConfig.Value?.JsonSerializerSettings);
+		}
+	}
+
+}

+ 113 - 0
JsonRPC4/Router/Defaults/DefaultRpcResponseSerializer.cs

@@ -0,0 +1,113 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class DefaultRpcResponseSerializer : IRpcResponseSerializer
+	{
+		private IOptions<RpcServerConfiguration> serverConfig
+		{
+			get;
+		}
+
+		public DefaultRpcResponseSerializer(IOptions<RpcServerConfiguration> serverConfig)
+		{
+			this.serverConfig = serverConfig;
+		}
+
+		public Task SerializeBulkAsync(IEnumerable<RpcResponse> responses, Stream stream)
+		{
+			return SerializeInternalAsync(responses, isBulkRequest: true, stream);
+		}
+
+		public Task SerializeAsync(RpcResponse response, Stream stream)
+		{
+			return SerializeInternalAsync(new RpcResponse[1]
+			{
+			response
+			}, isBulkRequest: false, stream);
+		}
+
+		private async Task SerializeInternalAsync(IEnumerable<RpcResponse> responses, bool isBulkRequest, Stream stream)
+		{
+			Utf8JsonWriter jsonWriter = (Utf8JsonWriter)(object)new Utf8JsonWriter(stream, default(JsonWriterOptions));
+			try
+			{
+				if (isBulkRequest)
+				{
+					jsonWriter.WriteStartArray();
+					foreach (RpcResponse response in responses)
+					{
+						SerializeResponse(response, jsonWriter);
+					}
+					jsonWriter.WriteEndArray();
+				}
+				else
+				{
+					SerializeResponse(responses.Single(), jsonWriter);
+				}
+			}
+			finally
+			{
+				await jsonWriter.FlushAsync(default(CancellationToken));
+				await jsonWriter.DisposeAsync();
+			}
+		}
+
+		private void SerializeResponse(RpcResponse response, Utf8JsonWriter jsonWriter)
+		{
+			jsonWriter.WriteStartObject();
+			jsonWriter.WritePropertyName("id");
+			switch (response.Id.Type)
+			{
+				case RpcIdType.Number:
+					jsonWriter.WriteNumberValue(response.Id.NumberValue);
+					break;
+				case RpcIdType.String:
+					jsonWriter.WriteStringValue(response.Id.StringValue);
+					break;
+				default:
+					throw new NotImplementedException();
+			}
+			jsonWriter.WriteString("jsonrpc", "2.0");
+			if (!response.HasError)
+			{
+				jsonWriter.WritePropertyName("result");
+				SerializeValue(response.Result, jsonWriter);
+			}
+			else
+			{
+				jsonWriter.WritePropertyName("error");
+				jsonWriter.WriteStartObject();
+				jsonWriter.WriteNumber("code", response.Error.Code);
+				jsonWriter.WriteString("message", response.Error.Message);
+				jsonWriter.WritePropertyName("data");
+				SerializeValue(response.Error.Data, jsonWriter);
+				jsonWriter.WriteEndObject();
+			}
+			jsonWriter.WriteEndObject();
+		}
+
+		private void SerializeValue(object value, Utf8JsonWriter jsonWriter)
+		{
+			if (value != null)
+			{
+				JsonSerializerOptions jsonSerializerSettings = serverConfig.Value.JsonSerializerSettings;
+				JsonDocument.Parse( JsonSerializer.SerializeToUtf8Bytes(value, value.GetType(), jsonSerializerSettings), default(JsonDocumentOptions)).WriteTo(jsonWriter);
+			}
+			else
+			{
+				jsonWriter.WriteNullValue();
+			}
+		}
+	}
+
+}

+ 18 - 0
JsonRPC4/Router/Defaults/JsonBytesSequenceSegment.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	internal class JsonBytesSequenceSegment : ReadOnlySequenceSegment<byte>
+	{
+		// Token: 0x06000102 RID: 258 RVA: 0x00004E2C File Offset: 0x0000302C
+		public JsonBytesSequenceSegment(Memory<byte> bytes, JsonBytesSequenceSegment next = null)
+		{
+			base.Memory = bytes;
+			base.Next = next;
+		}
+	}
+}

+ 24 - 0
JsonRPC4/Router/Defaults/RpcEndpointInfo.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class RpcEndpointInfo
+	{
+		
+		public Dictionary<RpcPath, List<MethodInfo>> Routes { get; }
+
+		// Token: 0x060000D3 RID: 211 RVA: 0x00003A40 File Offset: 0x00001C40
+		public RpcEndpointInfo(Dictionary<RpcPath, List<MethodInfo>> routes)
+		{
+			if (routes == null)
+			{
+				throw new ArgumentNullException("routes");
+			}
+			this.Routes = routes;
+		}
+	}
+}

+ 37 - 0
JsonRPC4/Router/Defaults/RpcMethodErrorResult.cs

@@ -0,0 +1,37 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class RpcMethodErrorResult : IRpcMethodResult
+	{
+		public string Message { get; }
+
+		// Token: 0x17000051 RID: 81
+		// (get) Token: 0x060000F5 RID: 245 RVA: 0x00004770 File Offset: 0x00002970
+		public int ErrorCode { get; }
+
+		// Token: 0x17000052 RID: 82
+		// (get) Token: 0x060000F6 RID: 246 RVA: 0x00004778 File Offset: 0x00002978
+		public object Data { get; }
+
+		// Token: 0x060000F7 RID: 247 RVA: 0x00004780 File Offset: 0x00002980
+		public RpcMethodErrorResult(int errorCode, string message = null, object data = null)
+		{
+			this.ErrorCode = errorCode;
+			this.Message = message;
+			this.Data = data;
+		}
+
+		// Token: 0x060000F8 RID: 248 RVA: 0x000047A0 File Offset: 0x000029A0
+		public RpcResponse ToRpcResponse(RpcId id)
+		{
+			RpcError error = new RpcError(this.ErrorCode, this.Message, this.Data);
+			return new RpcResponse(id, error);
+		}
+	}
+}

+ 25 - 0
JsonRPC4/Router/Defaults/RpcMethodSuccessResult.cs

@@ -0,0 +1,25 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Defaults
+{
+	public class RpcMethodSuccessResult : IRpcMethodResult
+	{
+		public object ReturnObject { get; }
+
+		public RpcMethodSuccessResult(object returnObject = null)
+		{
+			this.ReturnObject = returnObject;
+		}
+
+		// Token: 0x060000FB RID: 251 RVA: 0x000047E3 File Offset: 0x000029E3
+		public RpcResponse ToRpcResponse(RpcId id)
+		{
+			return new RpcResponse(id, this.ReturnObject);
+		}
+	}
+}

+ 18 - 0
JsonRPC4/Router/IRpcParameter.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public interface IRpcParameter
+	{
+		RpcParameterType Type
+		{
+			get;
+		}
+
+		bool TryGetValue(Type type, out object value);
+	}
+
+}

+ 53 - 0
JsonRPC4/Router/JsonBytesRpcParameter.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class JsonBytesRpcParameter : IRpcParameter
+	{
+		public RpcParameterType Type
+		{
+			get;
+		}
+
+		private Memory<byte> bytes
+		{
+			get;
+		}
+
+		private JsonSerializerOptions serializerOptions
+		{
+			get;
+		}
+
+		public JsonBytesRpcParameter(RpcParameterType type, Memory<byte> bytes, JsonSerializerOptions serializerOptions = null)
+		{
+			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
+			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
+			Type = type;
+			this.bytes = bytes;
+			this.serializerOptions = serializerOptions;
+		}
+
+		public bool TryGetValue(Type type, out object value)
+		{
+			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
+			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
+			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
+			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
+			try
+			{
+				value = JsonSerializer.Deserialize(this.bytes.Span, type, this.serializerOptions);
+				return true;
+			}
+			catch (Exception)
+			{
+				value = null;
+				return false;
+			}
+		}
+	}
+}

+ 47 - 0
JsonRPC4/Router/OnExceptionResult.cs

@@ -0,0 +1,47 @@
+using JsonRPC4.Router.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+    public class OnExceptionResult
+    {
+		public bool ThrowException
+		{
+			get;
+		}
+
+		public object ResponseObject
+		{
+			get;
+		}
+
+		private OnExceptionResult(bool throwException, object responseObject)
+		{
+			ThrowException = throwException;
+			ResponseObject = responseObject;
+		}
+
+		public static OnExceptionResult UseObjectResponse(object responseObject)
+		{
+			return new OnExceptionResult(throwException: false, responseObject);
+		}
+
+		public static OnExceptionResult UseMethodResultResponse(IRpcMethodResult result)
+		{
+			return new OnExceptionResult(throwException: false, result);
+		}
+
+		public static OnExceptionResult UseExceptionResponse(Exception ex)
+		{
+			return new OnExceptionResult(throwException: true, ex);
+		}
+
+		public static OnExceptionResult DontHandle()
+		{
+			return new OnExceptionResult(throwException: true, null);
+		}
+	}
+}

+ 54 - 0
JsonRPC4/Router/ParsingResult.cs

@@ -0,0 +1,54 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class ParsingResult
+	{
+		public List<RpcRequest> Requests
+		{
+			get;
+		}
+
+		public List<(RpcId Id, RpcError Error)> Errors
+		{
+			get;
+		}
+
+		public bool IsBulkRequest
+		{
+			get;
+		}
+
+		public int RequestCount => Requests.Count + Errors.Count;
+
+		public ParsingResult(List<RpcRequest> requests, List<(RpcId, RpcError)> errors, bool isBulkRequest)
+		{
+			Requests = requests;
+			Errors = errors;
+			IsBulkRequest = isBulkRequest;
+		}
+
+		internal static ParsingResult FromResults(List<RpcRequestParseResult> results, bool isBulkRequest)
+		{
+			List<RpcRequest> list = new List<RpcRequest>();
+			List<(RpcId, RpcError)> list2 = new List<(RpcId, RpcError)>();
+			foreach (RpcRequestParseResult result in results)
+			{
+				if (result.Error != null)
+				{
+					list2.Add((result.Id, result.Error));
+				}
+				else
+				{
+					list.Add(new RpcRequest(result.Id, result.Method, result.Parameters));
+				}
+			}
+			isBulkRequest = (isBulkRequest || list.Count + list2.Count > 1);
+			return new ParsingResult(list, list2, isBulkRequest);
+		}
+	}
+}

+ 60 - 0
JsonRPC4/Router/RawRpcParameter.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RawRpcParameter : IRpcParameter
+	{
+		public RpcParameterType Type
+		{
+			get;
+		}
+
+		public object Value
+		{
+			get;
+		}
+
+		public RawRpcParameter(RpcParameterType type, object value)
+		{
+			Type = type;
+			Value = value;
+		}
+
+		public bool TryGetValue(Type type, out object value)
+		{
+			if (Type == RpcParameterType.Null)
+			{
+				value = null;
+				return false;
+			}
+			if (Value == null)
+			{
+				value = null;
+				return false;
+			}
+			Type type2 = Value.GetType();
+			if (type2 == type)
+			{
+				value = Value;
+				return true;
+			}
+			TypeConverter converter = TypeDescriptor.GetConverter(type);
+			if (converter != null && converter.CanConvertFrom(type2))
+			{
+				value = converter.ConvertFrom(Value);
+				return true;
+			}
+			if (TypeDescriptor.GetConverter(type2) != null && converter.CanConvertTo(type2))
+			{
+				value = converter.ConvertTo(Value, type);
+				return true;
+			}
+			value = null;
+			return false;
+		}
+	}
+}

+ 15 - 0
JsonRPC4/Router/RpcCanceledRequestException.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcCanceledRequestException : RpcRouterException
+	{
+		public RpcCanceledRequestException(string message, Exception ex = null)
+			: base(message, ex)
+		{
+		}
+	}
+}

+ 15 - 0
JsonRPC4/Router/RpcConfigurationException.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcConfigurationException : RpcRouterException
+	{
+		public RpcConfigurationException(string message)
+			: base(message)
+		{
+		}
+	}
+}

+ 22 - 0
JsonRPC4/Router/RpcController.cs

@@ -0,0 +1,22 @@
+using JsonRPC4.Router.Defaults;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public abstract class RpcController
+	{
+		public virtual RpcMethodSuccessResult Ok(object obj = null)
+		{
+			return new RpcMethodSuccessResult(obj);
+		}
+
+		public virtual RpcMethodErrorResult Error(int errorCode, string message = null, object data = null)
+		{
+			return new RpcMethodErrorResult(errorCode, message, data);
+		}
+	}
+
+}

+ 88 - 0
JsonRPC4/Router/RpcEndpointBuilder.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+
+	public class RpcEndpointBuilder
+	{
+		private List<MethodInfo> baseMethods
+		{
+			get;
+		} = new List<MethodInfo>();
+
+
+		private Dictionary<RpcPath, List<MethodInfo>> methods
+		{
+			get;
+		} = new Dictionary<RpcPath, List<MethodInfo>>();
+
+
+		public RpcEndpointBuilder AddMethod(RpcPath path, MethodInfo methodInfo)
+		{
+			Add(path, methodInfo);
+			return this;
+		}
+
+		public RpcEndpointBuilder AddControllerWithDefaultPath<T>()
+		{
+			Type typeFromHandle = typeof(T);
+			return AddControllerWithDefaultPath(typeFromHandle);
+		}
+
+		public RpcEndpointBuilder AddControllerWithDefaultPath(Type controllerType)
+		{
+			RpcRouteAttribute customAttribute = controllerType.GetCustomAttribute<RpcRouteAttribute>(inherit: true);
+			ReadOnlySpan<char> path = (customAttribute != null && customAttribute.RouteName != null) ? MemoryExtensions.AsSpan(customAttribute.RouteName) : ((!controllerType.Name.EndsWith("Controller")) ? MemoryExtensions.AsSpan(controllerType.Name) : MemoryExtensions.AsSpan(controllerType.Name, 0, controllerType.Name.IndexOf("Controller")));
+			RpcPath path2 = RpcPath.Parse(path);
+			return AddController(controllerType, path2);
+		}
+
+		public RpcEndpointBuilder AddController<T>(RpcPath path = null)
+		{
+			Type typeFromHandle = typeof(T);
+			return AddController(typeFromHandle, path);
+		}
+
+		public RpcEndpointBuilder AddController(Type type, RpcPath path = null)
+		{
+			foreach (MethodInfo item in Extract(type))
+			{
+				Add(path, item);
+			}
+			return this;
+		}
+
+		public IRpcMethodProvider Resolve()
+		{
+			return new StaticRpcMethodProvider(baseMethods, methods);
+		}
+
+		private IEnumerable<MethodInfo> Extract(Type controllerType)
+		{
+			return from m in (from t in controllerType.Assembly.GetTypes()
+							  where t == controllerType
+							  select t).SelectMany((Type t) => t.GetMethods(BindingFlags.Instance | BindingFlags.Public))
+				   where m.DeclaringType != typeof(object)
+				   select m;
+		}
+
+		private void Add(RpcPath path, MethodInfo methodInfo)
+		{
+			List<MethodInfo> value;
+			if (path == null)
+			{
+				value = baseMethods;
+			}
+			else if (!methods.TryGetValue(path, out value))
+			{
+				List<MethodInfo> list2 = methods[path] = new List<MethodInfo>();
+				value = list2;
+			}
+			value.Add(methodInfo);
+		}
+	}
+}

+ 13 - 0
JsonRPC4/Router/RpcErrorFilterAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+    public abstract class RpcErrorFilterAttribute : Attribute
+    {
+        public abstract OnExceptionResult OnException(RpcRouteInfo routeInfo, Exception ex);
+    }
+
+}

+ 109 - 0
JsonRPC4/Router/RpcHttpRouter.cs

@@ -0,0 +1,109 @@
+using JsonRPC4.Common.Tools;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Defaults;
+using JsonRPC4.Router.Utilities;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcHttpRouter : IRouter
+	{
+		private static readonly char[] encodingSeperators = new char[2]
+		{
+		',',
+		' '
+		};
+
+		private IRpcMethodProvider methodProvider
+		{
+			get;
+		}
+
+		public RpcHttpRouter(IRpcMethodProvider methodProvider)
+		{
+			this.methodProvider = methodProvider;
+		}
+
+		public VirtualPathData GetVirtualPath(VirtualPathContext context)
+		{
+			return null;
+		}
+
+		public async Task RouteAsync(RouteContext context)
+		{
+			ILogger<RpcHttpRouter> logger = context.HttpContext.RequestServices.GetService<ILogger<RpcHttpRouter>>();
+			try
+			{
+				RpcPath requestPath;
+				if (!context.HttpContext.Request.Path.HasValue)
+				{
+					requestPath = null;
+					goto IL_00d3;
+				}
+				if (RpcPath.TryParse(MemoryExtensions.AsSpan(context.HttpContext.Request.Path.Value), out requestPath))
+				{
+					goto IL_00d3;
+				}
+				logger?.LogInformation("Could not parse the path '" + context.HttpContext.Request.Path.Value + "' for the request into an rpc path. Skipping rpc router middleware.");
+				goto end_IL_0035;
+			IL_00d3:
+				logger?.LogInformation($"Rpc request with route '{requestPath}' started.");
+				IRpcRequestHandler requestHandler = context.HttpContext.RequestServices.GetRequiredService<IRpcRequestHandler>();
+				IRouteContext routeContext = DefaultRouteContext.FromHttpContext(context.HttpContext, methodProvider);
+				Stream writableStream = BuildWritableResponseStream(context.HttpContext);
+				using (MemoryStream requestBody = new MemoryStream())
+				{
+					await context.HttpContext.Request.Body.CopyToAsync(requestBody);
+					requestBody.Position = 0L;
+					if (!(await requestHandler.HandleRequestAsync(requestPath, requestBody, routeContext, writableStream)))
+					{
+						context.HttpContext.Response.StatusCode = 204;
+						context.MarkAsHandled();
+						return;
+					}
+				}
+				context.MarkAsHandled();
+				logger?.LogInformation("Rpc request complete");
+			end_IL_0035:;
+			}
+			catch (Exception ex)
+			{
+				string message = "Unknown exception occurred when trying to process Rpc request. Marking route unhandled";
+				logger?.LogException(ex, message);
+				context.MarkAsHandled();
+			}
+		}
+
+		private Stream BuildWritableResponseStream(HttpContext httpContext)
+		{
+			httpContext.Response.ContentType = "application/json";
+			string text = httpContext.Request.Headers["Accept-Encoding"];
+			if (!string.IsNullOrWhiteSpace(text))
+			{
+				IStreamCompressor service = httpContext.RequestServices.GetService<IStreamCompressor>();
+				if (service != null)
+				{
+					string[] array = text.Split(encodingSeperators, StringSplitOptions.RemoveEmptyEntries);
+					foreach (string text2 in array)
+					{
+						if (service.TryGetCompressionStream(httpContext.Response.Body, text2, CompressionMode.Compress, out Stream compressedStream))
+						{
+							httpContext.Response.Headers.Add("Content-Encoding", text2);
+							return compressedStream;
+						}
+					}
+				}
+			}
+			return httpContext.Response.Body;
+		}
+	}
+}

+ 28 - 0
JsonRPC4/Router/RpcMethodInfo.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcMethodInfo
+	{
+		public MethodInfo Method
+		{
+			get;
+		}
+
+		public object[] Parameters
+		{
+			get;
+		}
+
+		public RpcMethodInfo(MethodInfo method, object[] parameters)
+		{
+			Method = method;
+			Parameters = parameters;
+		}
+	}
+
+}

+ 21 - 0
JsonRPC4/Router/RpcParameterExtensions.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+    public static class RpcParameterExtensions
+    {
+		public static bool TryGetValue<T>(this IRpcParameter parameter, out T value)
+		{
+			if (parameter.TryGetValue(typeof(T), out object value2))
+			{
+				value = (T)value2;
+				return true;
+			}
+			value = default(T);
+			return false;
+		}
+	}
+}

+ 15 - 0
JsonRPC4/Router/RpcParameterType.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public enum RpcParameterType
+	{
+		Null,
+		Number,
+		String,
+		Object
+	}
+}

+ 64 - 0
JsonRPC4/Router/RpcParameters.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcParameters
+	{
+		public object Value
+		{
+			get;
+		}
+
+		public bool IsDictionary
+		{
+			get;
+		}
+
+		public Dictionary<string, IRpcParameter> AsDictionary
+		{
+			get
+			{
+				CheckValue(isDictionary: true);
+				return (Dictionary<string, IRpcParameter>)Value;
+			}
+		}
+
+		public List<IRpcParameter> AsList
+		{
+			get
+			{
+				CheckValue(isDictionary: false);
+				return (List<IRpcParameter>)Value;
+			}
+		}
+
+		public RpcParameters(Dictionary<string, IRpcParameter> parameters)
+		{
+			Value = (parameters ?? throw new ArgumentNullException("parameters"));
+			IsDictionary = true;
+		}
+
+		public RpcParameters(List<IRpcParameter> parameters)
+		{
+			Value = (parameters ?? throw new ArgumentNullException("parameters"));
+			IsDictionary = false;
+		}
+
+		public RpcParameters(params IRpcParameter[] parameters)
+		{
+			Value = (parameters?.ToList() ?? throw new ArgumentNullException("parameters"));
+			IsDictionary = false;
+		}
+
+		private void CheckValue(bool isDictionary)
+		{
+			if (isDictionary != IsDictionary)
+			{
+				throw new InvalidOperationException();
+			}
+		}
+	}
+}

+ 220 - 0
JsonRPC4/Router/RpcPath.cs

@@ -0,0 +1,220 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+
+	public class RpcPath : IEquatable<RpcPath>
+	{
+		private char[] path;
+
+		private int? hashCodeCache;
+
+		private RpcPath(char[] path)
+		{
+			if (path == null || path.Length < 1)
+			{
+				throw new ArgumentNullException("path");
+			}
+			this.path = path;
+		}
+
+		public static bool operator ==(RpcPath path1, RpcPath path2)
+		{
+			return path1?.Equals(path2) ?? ((object)path2 == null);
+		}
+
+		public static bool operator !=(RpcPath path1, RpcPath path2)
+		{
+			return !(path1 == path2);
+		}
+
+		public bool StartsWith(RpcPath other)
+		{
+			if (other == null)
+			{
+				return true;
+			}
+			if (other.path.Length > path.Length)
+			{
+				return false;
+			}
+			for (int i = 0; i < other.path.Length; i++)
+			{
+				if (other.path[i] != path[i])
+				{
+					return false;
+				}
+			}
+			return true;
+		}
+
+		public bool Equals(RpcPath other)
+		{
+			if ((object)other == null)
+			{
+				return false;
+			}
+			return GetHashCode() == other.GetHashCode();
+		}
+
+		public override bool Equals(object obj)
+		{
+			RpcPath rpcPath = obj as RpcPath;
+			if ((object)rpcPath != null)
+			{
+				return Equals(rpcPath);
+			}
+			return false;
+		}
+
+		public override int GetHashCode()
+		{
+			if (!hashCodeCache.HasValue)
+			{
+				int num = 1337;
+				char[] array = path;
+				foreach (char c in array)
+				{
+					num = num * 7 + c.GetHashCode();
+				}
+				hashCodeCache = num;
+			}
+			return hashCodeCache.Value;
+		}
+
+		public static RpcPath Parse(ReadOnlySpan<char> path)
+		{
+			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
+			if (!TryParse(path, out RpcPath rpcPath))
+			{
+				throw new RpcException(RpcErrorCode.ParseError, "Rpc path could not be parsed from '" + new string(path.ToArray()) + "'.");
+			}
+			return rpcPath;
+		}
+
+		public    static bool TryParse(ReadOnlySpan<char> path, out RpcPath rpcPath)
+		{
+			if (path.IsEmpty)
+			{
+				rpcPath = null;
+				return true;
+			}
+			try
+			{
+				 
+				int num = IsSlash(path[0]) ? 1 : 0;
+				if (path.Length <= num)
+				{
+					rpcPath = null;
+					return true;
+				}
+				int num2 = IsSlash( path[path.Length - 1]) ? (path.Length- 1) : path.Length;
+				if (num >= num2 - 1)
+				{
+					rpcPath = null;
+					return true;
+				}
+				char[] array = new char[num2 - num];
+				int num3 = 0;
+				for (int i = num; i < num2; i++)
+				{
+					if (char.IsWhiteSpace(path[i]))
+					{
+						rpcPath = null;
+						return false;
+					}
+					char c2 = array[num3] = (!IsSlash(path[i])) ? char.ToLowerInvariant(path[i]) : '/';
+					num3++;
+				}
+				rpcPath = new RpcPath(array);
+				return true;
+			}
+			catch
+			{
+				rpcPath = null;
+				return false;
+			}
+			bool IsSlash(char c)
+			{
+				if (c != '/')
+				{
+					return c == '\\';
+				}
+				return true;
+			}
+		}
+
+		public RpcPath RemoveBasePath(RpcPath basePath)
+		{
+			if (!TryRemoveBasePath(basePath, out RpcPath result))
+			{
+				throw new RpcException(RpcErrorCode.ParseError, $"Count not remove path '{basePath}' from path '{this}'.");
+			}
+			return result;
+		}
+
+		public bool TryRemoveBasePath(RpcPath basePath, out RpcPath path)
+		{
+			if (basePath == null)
+			{
+				path = Clone();
+				return true;
+			}
+			if (!StartsWith(basePath))
+			{
+				path = null;
+				return false;
+			}
+			int num = this.path.Length - basePath.path.Length;
+			if (num < 1)
+			{
+				path = null;
+				return true;
+			}
+			char[] array = new char[num - 1];
+			MemoryExtensions.AsSpan<char>(this.path, basePath.path.Length + 1).CopyTo(array);
+			path = new RpcPath(array);
+			return true;
+		}
+
+		public RpcPath Add(RpcPath other)
+		{
+			if (other == null)
+			{
+				return Clone();
+			}
+			char[] array = new char[path.Length + other.path.Length + 1];
+			path.CopyTo(array, 0);
+			array[path.Length] = '/';
+			other.path.CopyTo(array, path.Length + 1);
+			return new RpcPath(array);
+		}
+
+		public override string ToString()
+		{
+			return new string(path);
+		}
+
+		public RpcPath Clone()
+		{
+			char[] array = new char[path.Length];
+			path.CopyTo(array, 0);
+			return new RpcPath(array);
+		}
+
+		public static implicit operator string(RpcPath path)
+		{
+			return path.ToString();
+		}
+
+		public static implicit operator RpcPath(string s)
+		{
+			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
+			return Parse(MemoryExtensions.AsSpan(s));
+		}
+	}
+}

+ 33 - 0
JsonRPC4/Router/RpcRequest.cs

@@ -0,0 +1,33 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcRequest
+	{
+		public RpcId Id
+		{
+			get;
+		}
+
+		public string Method
+		{
+			get;
+		}
+
+		public RpcParameters Parameters
+		{
+			get;
+		}
+
+		public RpcRequest(RpcId id, string method, RpcParameters parameters = null)
+		{
+			Id = id;
+			Method = method;
+			Parameters = parameters;
+		}
+	}
+}

+ 122 - 0
JsonRPC4/Router/RpcRequestHandler.cs

@@ -0,0 +1,122 @@
+using JsonRPC4.Common;
+using JsonRPC4.Router.Abstractions;
+using JsonRPC4.Router.Utilities;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcRequestHandler : IRpcRequestHandler
+	{
+		// Token: 0x17000032 RID: 50
+		// (get) Token: 0x06000096 RID: 150 RVA: 0x000032A5 File Offset: 0x000014A5
+		private IOptions<RpcServerConfiguration> serverConfig { get; }
+
+		// Token: 0x17000033 RID: 51
+		// (get) Token: 0x06000097 RID: 151 RVA: 0x000032AD File Offset: 0x000014AD
+		private IRpcInvoker invoker { get; }
+
+		// Token: 0x17000034 RID: 52
+		// (get) Token: 0x06000098 RID: 152 RVA: 0x000032B5 File Offset: 0x000014B5
+		private IRpcParser parser { get; }
+
+		// Token: 0x17000035 RID: 53
+		// (get) Token: 0x06000099 RID: 153 RVA: 0x000032BD File Offset: 0x000014BD
+		private ILogger<RpcRequestHandler> logger { get; }
+
+		// Token: 0x17000036 RID: 54
+		// (get) Token: 0x0600009A RID: 154 RVA: 0x000032C5 File Offset: 0x000014C5
+		private IRpcResponseSerializer responseSerializer { get; }
+
+		// Token: 0x0600009B RID: 155 RVA: 0x000032D0 File Offset: 0x000014D0
+		public RpcRequestHandler(IOptions<RpcServerConfiguration> serverConfig, IRpcInvoker invoker, IRpcParser parser, IRpcResponseSerializer responseSerializer, ILogger<RpcRequestHandler> logger)
+		{
+			if (serverConfig == null)
+			{
+				throw new ArgumentNullException("serverConfig");
+			}
+			this.serverConfig = serverConfig;
+			if (invoker == null)
+			{
+				throw new ArgumentNullException("invoker");
+			}
+			this.invoker = invoker;
+			if (parser == null)
+			{
+				throw new ArgumentNullException("parser");
+			}
+			this.parser = parser;
+			if (responseSerializer == null)
+			{
+				throw new ArgumentNullException("responseSerializer");
+			}
+			this.responseSerializer = responseSerializer;
+			this.logger = logger;
+		}
+
+		// Token: 0x0600009C RID: 156 RVA: 0x00003344 File Offset: 0x00001544
+		public async Task<bool> HandleRequestAsync(RpcPath requestPath, Stream requestBody, IRouteContext routeContext, Stream responseBody)
+		{
+			try
+			{
+				ParsingResult result = parser.ParseRequests(requestBody);
+				logger.ProcessingRequests(result.RequestCount);
+				int? batchRequestLimit = serverConfig.Value.BatchRequestLimit;
+				new List<RpcResponse>();
+				List<RpcResponse> list;
+				if (batchRequestLimit > 0 && result.RequestCount > batchRequestLimit)
+				{
+					string text = $"Request count exceeded batch request limit ({batchRequestLimit}).";
+					list = new List<RpcResponse>
+				{
+					new RpcResponse(null, new RpcError(RpcErrorCode.InvalidRequest, text))
+				};
+					logger.LogError(text + " Returning error response.");
+				}
+				else
+				{
+					list = ((!result.Requests.Any()) ? new List<RpcResponse>() : (await invoker.InvokeBatchRequestAsync(result.Requests, routeContext, requestPath)));
+					foreach (var error in result.Errors)
+					{
+						RpcId item = error.Id;
+						RpcError item2 = error.Error;
+						if (item == default(RpcId))
+						{
+							logger.ResponseFailedWithNoId(item2.Code, item2.Message);
+						}
+						else
+						{
+							list.Add(new RpcResponse(item, item2));
+						}
+					}
+				}
+				if (list == null || !list.Any())
+				{
+					logger.NoResponses();
+					return false;
+				}
+				logger.Responses(list.Count);
+				if (!result.IsBulkRequest)
+				{
+					await responseSerializer.SerializeAsync(list.Single(), responseBody);
+				}
+				else
+				{
+					await responseSerializer.SerializeBulkAsync(list, responseBody);
+				}
+			}
+			catch (RpcException ex)
+			{
+				logger.LogException(ex, "Error occurred when proccessing Rpc request. Sending Rpc error response");
+				RpcResponse response = new RpcResponse(null, ex.ToRpcError(serverConfig.Value.ShowServerExceptions));
+				await responseSerializer.SerializeAsync(response, responseBody);
+			}
+			return true;
+		}
+	}
+}

+ 50 - 0
JsonRPC4/Router/RpcRequestParseResult.cs

@@ -0,0 +1,50 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	internal class RpcRequestParseResult
+	{
+		public RpcId Id
+		{
+			get;
+		}
+
+		public string Method
+		{
+			get;
+		}
+
+		public RpcParameters Parameters
+		{
+			get;
+		}
+
+		public RpcError Error
+		{
+			get;
+		}
+
+		private RpcRequestParseResult(RpcId id, string method, RpcParameters parameters, RpcError error)
+		{
+			Id = id;
+			Method = method;
+			Parameters = parameters;
+			Error = error;
+		}
+
+		public static RpcRequestParseResult Success(RpcId id, string method, RpcParameters parameters)
+		{
+			return new RpcRequestParseResult(id, method, parameters, null);
+		}
+
+		public static RpcRequestParseResult Fail(RpcId id, RpcError error)
+		{
+			return new RpcRequestParseResult(id, null, null, error);
+		}
+	}
+
+}

+ 60 - 0
JsonRPC4/Router/RpcResponse.cs

@@ -0,0 +1,60 @@
+using JsonRPC4.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+    public class RpcResponse
+    {
+		public RpcId Id
+		{
+			get;
+			private set;
+		}
+
+		public object Result
+		{
+			get;
+			private set;
+		}
+
+		public RpcError Error
+		{
+			get;
+			private set;
+		}
+
+		public bool HasError => Error != null;
+
+		protected RpcResponse()
+		{
+		}
+
+		protected RpcResponse(RpcId id)
+		{
+			Id = id;
+		}
+
+		public RpcResponse(RpcId id, RpcError error)
+			: this(id)
+		{
+			Error = error;
+		}
+
+		public RpcResponse(RpcId id, object result)
+			: this(id)
+		{
+			Result = result;
+		}
+
+		public void ThrowErrorIfExists()
+		{
+			if (HasError)
+			{
+				throw Error.CreateException();
+			}
+		}
+	}
+}

+ 17 - 0
JsonRPC4/Router/RpcRouteAttribute.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcRouteAttribute : Attribute
+	{
+		public string RouteName { get; }
+
+		public RpcRouteAttribute(string routeName = null)
+		{
+			this.RouteName = ((routeName != null) ? routeName.Trim() : null);
+		}
+	}
+}

+ 33 - 0
JsonRPC4/Router/RpcRouteInfo.cs

@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcRouteInfo
+	{
+		public RpcMethodInfo MethodInfo
+		{
+			get;
+		}
+
+		public RpcPath Path
+		{
+			get;
+		}
+
+		public IServiceProvider RequestServices
+		{
+			get;
+		}
+
+		internal RpcRouteInfo(RpcMethodInfo methodInfo, RpcPath path, IServiceProvider requestServices)
+		{
+			MethodInfo = methodInfo;
+			Path = path;
+			RequestServices = requestServices;
+		}
+	}
+
+}

+ 14 - 0
JsonRPC4/Router/RpcRouterException.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public abstract class RpcRouterException : Exception
+	{
+		protected RpcRouterException(string message, Exception ex = null) : base(message, ex)
+		{
+		}
+	}
+}

+ 30 - 0
JsonRPC4/Router/RpcServerConfiguration.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	public class RpcServerConfiguration
+	{
+		public JsonSerializerOptions JsonSerializerSettings
+		{
+			get;
+			set;
+		}
+
+		public bool ShowServerExceptions
+		{
+			get;
+			set;
+		}
+
+		public int? BatchRequestLimit
+		{
+			get;
+			set;
+		}
+	}
+
+}

+ 44 - 0
JsonRPC4/Router/StaticRpcMethodProvider.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router
+{
+	internal class StaticRpcMethodProvider : IRpcMethodProvider
+	{
+		// Token: 0x1700003E RID: 62
+		// (get) Token: 0x060000B0 RID: 176 RVA: 0x00003488 File Offset: 0x00001688
+		private List<MethodInfo> baseMethods { get; }
+
+		// Token: 0x1700003F RID: 63
+		// (get) Token: 0x060000B1 RID: 177 RVA: 0x00003490 File Offset: 0x00001690
+		private Dictionary<RpcPath, List<MethodInfo>> methods { get; }
+
+		// Token: 0x060000B2 RID: 178 RVA: 0x00003498 File Offset: 0x00001698
+		public StaticRpcMethodProvider(List<MethodInfo> baseMethods, Dictionary<RpcPath, List<MethodInfo>> methods)
+		{
+			this.baseMethods = baseMethods;
+			this.methods = methods;
+		}
+
+		// Token: 0x060000B3 RID: 179 RVA: 0x000034B0 File Offset: 0x000016B0
+		public bool TryGetByPath(RpcPath path, out IReadOnlyList<MethodInfo> methods)
+		{
+			if (path == null)
+			{
+				methods = this.baseMethods;
+				return true;
+			}
+			List<MethodInfo> list;
+			if (this.methods.TryGetValue(path, out list))
+			{
+				methods = list;
+				return true;
+			}
+			methods = null;
+			return false;
+		}
+	}
+}

+ 198 - 0
JsonRPC4/Router/Utilities/LoggerExtensions.cs

@@ -0,0 +1,198 @@
+using JsonRPC4.Common;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Utilities
+{
+	public static class LoggerExtensions
+	{
+		private static readonly Action<ILogger, string, Exception> attemptingToMatchMethod;
+
+		private static readonly Action<ILogger, Exception> requestMatchedMethod;
+
+		private static readonly Action<ILogger, string, Exception> methodsInRoute;
+
+		private const LogLevel methodsInRouteLevel = LogLevel.Trace;
+
+		private static readonly Action<ILogger, int, Exception> invokingBatchRequests;
+
+		private static readonly Action<ILogger, Exception> batchRequestsComplete;
+
+		private static readonly Action<ILogger, RpcId, Exception> invokingRequest;
+
+		private static readonly Action<ILogger, string, Exception> invokeMethod;
+
+		private static readonly Action<ILogger, string, Exception> invokeMethodComplete;
+
+		private static readonly Action<ILogger, RpcId, Exception> finishedRequest;
+
+		private static readonly Action<ILogger, Exception> finishedRequestNoId;
+
+		private static readonly Action<ILogger, Exception> skippingAuth;
+
+		private static readonly Action<ILogger, Exception> runningAuth;
+
+		private static readonly Action<ILogger, Exception> authSuccessful;
+
+		private static readonly Action<ILogger, Exception> authFailed;
+
+		private static readonly Action<ILogger, Exception> noConfiguredAuth;
+
+		private static readonly Action<ILogger, Exception> parsingRequests;
+
+		private static readonly Action<ILogger, int, Exception> parsedRequests;
+
+		private static readonly Action<ILogger, int, Exception> processingRequests;
+
+		private static readonly Action<ILogger, int, string, Exception> responseFailedWithNoId;
+
+		private static readonly Action<ILogger, Exception> noResponses;
+
+		private static readonly Action<ILogger, int, Exception> responses;
+
+		static LoggerExtensions()
+		{
+			attemptingToMatchMethod = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(1, "AttemptingToMatchMethod"), "Attempting to match Rpc request to a method '{Method}'");
+			requestMatchedMethod = LoggerMessage.Define(LogLevel.Debug, new EventId(2, "RequestMatchedMethod"), "Request was matched to a method");
+			methodsInRoute = LoggerMessage.Define<string>(LogLevel.Trace, new EventId(3, "MethodsInRoute"), "Methods in route: {MethodsString}");
+			invokingBatchRequests = LoggerMessage.Define<int>(LogLevel.Debug, new EventId(4, "InvokingBatchRequests"), "Invoking '{Count}' batch requests");
+			batchRequestsComplete = LoggerMessage.Define(LogLevel.Debug, new EventId(5, "BatchRequestsComplete"), "Finished batch requests");
+			invokingRequest = LoggerMessage.Define<RpcId>(LogLevel.Debug, new EventId(6, "InvokingRequest"), "Invoking request with id '{Id}'");
+			invokeMethod = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(7, "InvokeMethod"), "Attempting to invoke method '{Method}'");
+			invokeMethodComplete = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(8, "InvokeMethodComplete"), "Finished invoking method '{Method}'");
+			finishedRequest = LoggerMessage.Define<RpcId>(LogLevel.Debug, new EventId(9, "FinishedRequest"), "Finished request with id: {Id}");
+			finishedRequestNoId = LoggerMessage.Define(LogLevel.Debug, new EventId(10, "FinishedRequestNoId"), "Finished request with no id. Not returning a response");
+			skippingAuth = LoggerMessage.Define(LogLevel.Debug, new EventId(11, "SkippingAuth"), "Skipping authorization. Allow anonymous specified for method.");
+			runningAuth = LoggerMessage.Define(LogLevel.Debug, new EventId(12, "RunningAuth"), "Running authorization for method.");
+			authSuccessful = LoggerMessage.Define(LogLevel.Debug, new EventId(13, "AuthSuccessful"), "Authorization was successful.");
+			authFailed = LoggerMessage.Define(LogLevel.Information, new EventId(14, "AuthFailed"), "Authorization failed.");
+			noConfiguredAuth = LoggerMessage.Define(LogLevel.Debug, new EventId(15, "NoConfiguredAuth"), "Skipping authorization. None configured for class or method.");
+			parsingRequests = LoggerMessage.Define(LogLevel.Debug, new EventId(16, "ParsingRequests"), "Attempting to parse Rpc request from the json");
+			parsedRequests = LoggerMessage.Define<int>(LogLevel.Debug, new EventId(17, "ParsedRequests"), "Successfully parsed {Count} Rpc request(s)");
+			processingRequests = LoggerMessage.Define<int>(LogLevel.Information, new EventId(18, "ProcessingRequests"), "Processing {Count} Rpc requests");
+			responseFailedWithNoId = LoggerMessage.Define<int, string>(LogLevel.Error, new EventId(19, "ResponseFailedWithNoId"), "Request with no id failed and no response will be sent. Error - Code: {Code}, Message: {Message}");
+			noResponses = LoggerMessage.Define(LogLevel.Information, new EventId(20, "NoResponses"), "No rpc responses created.");
+			responses = LoggerMessage.Define<int>(LogLevel.Information, new EventId(21, "Responses"), "{Count} rpc response(s) created.");
+		}
+
+		public static void LogException(this ILogger logger, Exception ex, string message = null)
+		{
+			message = ((message == null) ? $"{ex}" : $"{message}{Environment.NewLine}{ex}");
+			logger.LogError(default(EventId), ex, message);
+		}
+
+		public static void AttemptingToMatchMethod(this ILogger logger, string method)
+		{
+			attemptingToMatchMethod(logger, method, null);
+		}
+
+		public static void RequestMatchedMethod(this ILogger logger)
+		{
+			requestMatchedMethod(logger, null);
+		}
+
+		public static void MethodsInRoute(this ILogger logger, IEnumerable<MethodInfo> methods)
+		{
+			if (logger.IsEnabled(LogLevel.Trace))
+			{
+				string arg = string.Join(", ", methods.Select((MethodInfo m) => m.Name));
+				methodsInRoute(logger, arg, null);
+			}
+		}
+
+		public static void InvokingBatchRequests(this ILogger logger, int count)
+		{
+			invokingBatchRequests(logger, count, null);
+		}
+
+		public static void BatchRequestsComplete(this ILogger logger)
+		{
+			batchRequestsComplete(logger, null);
+		}
+
+		public static void InvokingRequest(this ILogger logger, RpcId id)
+		{
+			invokingRequest(logger, id, null);
+		}
+
+		public static void InvokeMethod(this ILogger logger, string method)
+		{
+			invokeMethod(logger, method, null);
+		}
+
+		public static void InvokeMethodComplete(this ILogger logger, string method)
+		{
+			invokeMethodComplete(logger, method, null);
+		}
+
+		public static void FinishedRequest(this ILogger logger, RpcId id)
+		{
+			finishedRequest(logger, id, null);
+		}
+
+		public static void FinishedRequestNoId(this ILogger logger)
+		{
+			finishedRequestNoId(logger, null);
+		}
+
+		public static void SkippingAuth(this ILogger logger)
+		{
+			skippingAuth(logger, null);
+		}
+
+		public static void RunningAuth(this ILogger logger)
+		{
+			runningAuth(logger, null);
+		}
+
+		public static void AuthSuccessful(this ILogger logger)
+		{
+			authSuccessful(logger, null);
+		}
+
+		public static void AuthFailed(this ILogger logger)
+		{
+			authFailed(logger, null);
+		}
+
+		public static void NoConfiguredAuth(this ILogger logger)
+		{
+			noConfiguredAuth(logger, null);
+		}
+
+		public static void ParsingRequests(this ILogger logger)
+		{
+			parsingRequests(logger, null);
+		}
+
+		public static void ParsedRequests(this ILogger logger, int count)
+		{
+			parsedRequests(logger, count, null);
+		}
+
+		public static void ProcessingRequests(this ILogger logger, int count)
+		{
+			processingRequests(logger, count, null);
+		}
+
+		public static void ResponseFailedWithNoId(this ILogger logger, int code, string message)
+		{
+			responseFailedWithNoId(logger, code, message, null);
+		}
+
+		public static void NoResponses(this ILogger logger)
+		{
+			noResponses(logger, null);
+		}
+
+		public static void Responses(this ILogger logger, int count)
+		{
+			responses(logger, count, null);
+		}
+	}
+
+}

+ 17 - 0
JsonRPC4/Router/Utilities/RouteContextExtensions.cs

@@ -0,0 +1,17 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Utilities
+{
+	public static class RouteContextExtensions
+	{
+		public static void MarkAsHandled(this RouteContext context)
+		{
+			context.Handler = ((HttpContext c) => Task.FromResult<int>(0));
+		}
+	}
+}

+ 45 - 0
JsonRPC4/Router/Utilities/RpcUtil.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Utilities
+{
+	public class RpcUtil
+	{
+		public static bool TypesMatch(object value, Type type)
+		{
+			Type underlyingType = Nullable.GetUnderlyingType(type);
+			if (underlyingType != null)
+			{
+				type = underlyingType;
+			}
+			return value?.GetType() == type;
+		}
+
+		public   static bool NamesMatch(ReadOnlySpan<char> actual, ReadOnlySpan<char> requested)
+		{
+			if (actual.Length > requested.Length)
+			{
+				return false;
+			}
+			int num = 0;
+			for (int i = 0; i < actual.Length; i++)
+			{
+				//char c = (char)(*(ushort*)requested.get_Item(num++));
+				char c = requested[num++];//(char)(*(ushort*)requested.get_Item(num++));
+				//if (char.ToLower((char)(*(ushort*)actual.get_Item(i))) != char.ToLower(c))
+				if(char.ToLower(actual[i])!=char.ToLower(c))
+				{
+					if (c != '-' && c != '_')
+					{
+						return false;
+					}
+					i--;
+				}
+			}
+			return num == actual.Length;
+		}
+	}
+
+}

+ 20 - 0
JsonRPC4/Router/Utilities/StreamUtil.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Utilities
+{
+	internal class StreamUtil
+	{
+		internal static MemoryStream GetStreamFromUtf8String(string utf8Text)
+		{
+			byte[] array = ArrayPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(utf8Text));
+			int bytes = Encoding.UTF8.GetBytes(utf8Text, 0, utf8Text.Length, array, 0);
+			return new MemoryStream(array, 0, bytes);
+		}
+	}
+}

+ 20 - 0
JsonRPC4/Router/Utilities/TypeExtensions.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPC4.Router.Utilities
+{
+	public static class TypeExtensions
+	{
+		public static bool IsNullableType(this Type type)
+		{
+			if (type.IsValueType)
+			{
+				return Nullable.GetUnderlyingType(type) != null;
+			}
+			return true;
+		}
+	}
+
+}

+ 47 - 0
JsonRPC4/Startup.cs

@@ -0,0 +1,47 @@
+
+using JsonRPC4.Builder;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace JsonRPC4
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddControllers();
+            services.AddJsonRpc();
+        }
+
+        // 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.UseJsonRpc();
+            app.UseHttpsRedirection();
+
+            app.UseRouting();
+
+            app.UseAuthorization();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapControllers();
+            });
+        }
+    }
+}

+ 15 - 0
JsonRPC4/WeatherForecast.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace JsonRPC4
+{
+    public class WeatherForecast
+    {
+        public DateTime Date { get; set; }
+
+        public int TemperatureC { get; set; }
+
+        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+        public string Summary { get; set; }
+    }
+}

+ 9 - 0
JsonRPC4/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}

+ 10 - 0
JsonRPC4/appsettings.json

@@ -0,0 +1,10 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*"
+}

+ 25 - 1
NETCore3Demo.sln

@@ -29,7 +29,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp4", "ConsoleApp4\
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{493EE831-364D-4106-BED8-AFA20189F8F3}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonRPCTest", "JsonRPCTest\JsonRPCTest.csproj", "{19B8EBD2-C014-4354-BDF4-0E1E896D007F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonRPCTest", "JsonRPCTest\JsonRPCTest.csproj", "{19B8EBD2-C014-4354-BDF4-0E1E896D007F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonRPC4", "JsonRPC4\JsonRPC4.csproj", "{8AED8803-B5DA-43B4-96DC-66033D8C69C2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyRpc", "EasyRpc\EasyRpc.csproj", "{7705F51B-743F-4E96-AAC3-1AD6163AD44A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aspnetcore-json-rpc", "aspnetcore-json-rpc\aspnetcore-json-rpc.csproj", "{1C823A05-6137-4EC4-8A85-76742ABC5663}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp5AliOSS", "ConsoleApp5AliOSS\ConsoleApp5AliOSS.csproj", "{6FDEDD86-A757-4952-A6B3-0BA1FD4FF6D6}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -93,6 +101,22 @@ Global
 		{19B8EBD2-C014-4354-BDF4-0E1E896D007F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{19B8EBD2-C014-4354-BDF4-0E1E896D007F}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{19B8EBD2-C014-4354-BDF4-0E1E896D007F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8AED8803-B5DA-43B4-96DC-66033D8C69C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8AED8803-B5DA-43B4-96DC-66033D8C69C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8AED8803-B5DA-43B4-96DC-66033D8C69C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8AED8803-B5DA-43B4-96DC-66033D8C69C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7705F51B-743F-4E96-AAC3-1AD6163AD44A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7705F51B-743F-4E96-AAC3-1AD6163AD44A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7705F51B-743F-4E96-AAC3-1AD6163AD44A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7705F51B-743F-4E96-AAC3-1AD6163AD44A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1C823A05-6137-4EC4-8A85-76742ABC5663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C823A05-6137-4EC4-8A85-76742ABC5663}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C823A05-6137-4EC4-8A85-76742ABC5663}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C823A05-6137-4EC4-8A85-76742ABC5663}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6FDEDD86-A757-4952-A6B3-0BA1FD4FF6D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6FDEDD86-A757-4952-A6B3-0BA1FD4FF6D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6FDEDD86-A757-4952-A6B3-0BA1FD4FF6D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6FDEDD86-A757-4952-A6B3-0BA1FD4FF6D6}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 13 - 0
WebTest/Controllers/Item.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPCTest.Controllers
+{
+    public class Item
+    {
+        public string aaa { get; set; }
+        public string ccc { get; set; }
+    }
+}

+ 13 - 0
WebTest/Controllers/Person.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPCTest.Controllers
+{
+    public class Person
+    {
+        public string name { get; set; }
+        public string age { get; set; }
+    }
+}

File diff ditekan karena terlalu besar
+ 55 - 100
WebTest/Controllers/WeatherForecastController.cs


+ 13 - 0
WebTest/JsonRPC/BaseJosnRPCRequest.cs

@@ -0,0 +1,13 @@
+
+using System;
+
+namespace TEAMModelOS.SDK.Extension.DataResult.JsonRpcRequest
+{
+    
+    public abstract class BaseJosnRPCRequest
+    {
+        public long requestTime { get; set; } = DateTime.Now.ToUniversalTime().Ticks - 621355968000000000;
+        public int timeOffset { get; set; }
+        public string lang { get; set; } = "zh-CN";
+    }
+}

+ 13 - 0
WebTest/JsonRPC/JosnRPCReq.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Extension.DataResult.JsonRpcRequest;
+
+namespace WebTest.JsonRPC
+{
+    public class JosnRPCReq<T> : BaseJosnRPCRequest
+    {
+        public T @params { get; set; }
+    }
+}

+ 13 - 0
WebTest/JsonRPC/JosnRPCRequest.cs

@@ -0,0 +1,13 @@
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Extension.DataResult.JsonRpcRequest
+{
+    
+    public class JosnRPCRequest<T>:BaseJosnRPCRequest
+    {
+        public T @params { get; set; }
+    }
+}

+ 3 - 1
WebTest/Startup.cs

@@ -25,7 +25,8 @@ namespace WebTest
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
-            services.AddControllers();
+            services.AddControllers().AddNewtonsoftJson();
+            services.AddJsonRpc();
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -35,6 +36,7 @@ namespace WebTest
             {
                 app.UseDeveloperExceptionPage();
             }
+            app.UseJsonRpc();
 
             app.UseHttpsRedirection();
 

+ 5 - 1
WebTest/WebTest.csproj

@@ -1,10 +1,14 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>
+    
+    <PackageReference Include="EdjCase.JsonRpc.Router" Version="3.1.0" />
+    
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
   </ItemGroup>
 

+ 13 - 0
aspnetcore-json-rpc/Controllers/Item.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace JsonRPCTest.Controllers
+{
+    public class Item
+    {
+        public string aaa { get; set; }
+        public string ccc { get; set; }
+    }
+}

+ 56 - 0
aspnetcore-json-rpc/Controllers/WeatherForecastController.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Anemonis.AspNetCore.JsonRpc;
+using JsonRPCTest.Controllers;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+namespace aspnetcore_json_rpc.Controllers
+{
+    
+    [JsonRpcRoute("/api")]
+    public class WeatherForecastController : IJsonRpcService
+    {
+        private static readonly string[] Summaries = new[]
+        {
+            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+        };
+
+        private readonly ILogger<WeatherForecastController> _logger;
+
+        public WeatherForecastController(ILogger<WeatherForecastController> logger)
+        {
+            _logger = logger;
+        }
+        [JsonRpcMethod("m1", "p1", "p2")]
+        public Task<long> InvokeMethod1Async(long p1, long p2)
+        {
+            if (p2 == 0L)
+            {
+                throw new JsonRpcServiceException(100L,"12");
+            }
+
+            return Task.FromResult(p1 / p2);
+        }
+
+        [JsonRpcMethod("m2", 0, 1)]
+        public Task<long> InvokeMethod2Async(long p1, long p2)
+        {
+            return Task.FromResult(p1 + p2);
+        }
+        [JsonRpcMethod("Gets", "item")]
+        public IEnumerable<WeatherForecast> Get(string item)
+        {
+            var rng = new Random();
+            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+            {
+                Date = DateTime.Now.AddDays(index),
+                TemperatureC = rng.Next(-20, 55),
+                Summary = Summaries[rng.Next(Summaries.Length)]
+            })
+            .ToArray();
+        }
+    }
+}

+ 26 - 0
aspnetcore-json-rpc/Program.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace aspnetcore_json_rpc
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                });
+    }
+}

+ 30 - 0
aspnetcore-json-rpc/Properties/launchSettings.json

@@ -0,0 +1,30 @@
+{
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:57685",
+      "sslPort": 44308
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "aspnetcore_json_rpc": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "weatherforecast",
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 0 - 0
aspnetcore-json-rpc/Startup.cs


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini