From fffb522f56612ef28ec8dfe5a0e232efbcb131f7 Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Mon, 18 Dec 2023 15:57:55 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Ipc=20=E5=85=83=E7=BB=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AssemblyLoad.Sample.EntryPoint/Program.cs | 5 +- .../Enums/MethodParametersCategory.cs | 6 +- .../Templates/Abstractions/IpcTemplateBase.cs | 36 ++++++++++++ .../Templates/IpcClientTemplate.cs | 55 +++++++++++++++++++ .../Program.cs | 18 ++++++ .../Templates/IpcServerTemplate.cs | 50 ++++++++++++++++- .../Helpers/TypeHelper.cs | 2 +- .../ITodoService.cs | 35 ++++++++++++ src/Ipc.Server.Sample.Experimental/Program.cs | 20 +++++++ 9 files changed, 220 insertions(+), 7 deletions(-) diff --git a/src/AssemblyLoad.Sample.EntryPoint/Program.cs b/src/AssemblyLoad.Sample.EntryPoint/Program.cs index a781ca2d8..c1fa2dc65 100644 --- a/src/AssemblyLoad.Sample.EntryPoint/Program.cs +++ b/src/AssemblyLoad.Sample.EntryPoint/Program.cs @@ -3,8 +3,7 @@ Console.WriteLine($"Environment.Version: {Environment.Version}"); // 从低版本的运行时中加载高版本的程序集 var libPath = string.Join(Path.DirectorySeparatorChar.ToString(), - new string[] - { + [ ProjPath.TrimEnd(Path.DirectorySeparatorChar), "src", "artifacts", @@ -12,7 +11,7 @@ "AssemblyLoad.Sample.Library", "debug", "AssemblyLoad.Sample.Library.dll", - }); + ]); var assembly = Assembly.LoadFile(libPath); var program = assembly.GetType("AssemblyLoad.Sample.Library.Program", true); var main = program.GetMethod("Main", BindingFlags.Static | BindingFlags.NonPublic); diff --git a/src/BD.Common8.SourceGenerator.Ipc.Client/Enums/MethodParametersCategory.cs b/src/BD.Common8.SourceGenerator.Ipc.Client/Enums/MethodParametersCategory.cs index 0e6e0e81f..3a6725fe5 100644 --- a/src/BD.Common8.SourceGenerator.Ipc.Client/Enums/MethodParametersCategory.cs +++ b/src/BD.Common8.SourceGenerator.Ipc.Client/Enums/MethodParametersCategory.cs @@ -64,7 +64,11 @@ public static MethodParametersCategory GetMethodParametersCategory(this IMethodS else if (method.Parameters.Length == 2 && new TypeStringImpl(method.Parameters[1].Type).IsSystemThreadingCancellationToken) return MethodParametersCategory.FromBody; - return MethodParametersCategory.GeneratorModelFromBody; + if (method.Parameters.Length <= 21 || + (method.Parameters.Length == 22 && + new TypeStringImpl(method.Parameters[21].Type).IsSystemThreadingCancellationToken)) + return MethodParametersCategory.GeneratorModelFromBody; // global::System.TupleExtensions.ToTuple 泛型仅支持最多 21 个参数 + return MethodParametersCategory.None; } /// diff --git a/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/Abstractions/IpcTemplateBase.cs b/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/Abstractions/IpcTemplateBase.cs index 397ea7a09..0120b9afe 100644 --- a/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/Abstractions/IpcTemplateBase.cs +++ b/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/Abstractions/IpcTemplateBase.cs @@ -192,4 +192,40 @@ MethodParametersCategory.FromBody or }; return requestMethod; } + + /// + /// 写入 + /// + /// + /// + protected void WriteTuple(Stream stream, MethodPara[] methodParas) + { + Tuple> a = default; + int endLen = 0; + for (int i = 0; i < methodParas.Length; i++) + { + var (paraType, _, _) = methodParas[i]; + if (i == methodParas.Length - 1) + { + if (paraType.IsSystemThreadingCancellationToken) + { + break; + } + } + if (i != 0) + { + stream.Write(", "u8); + } + if (i % 7 == 0) + { + stream.Write("Tuple<"u8); + endLen++; + } + stream.WriteUtf16StrToUtf8OrCustom(paraType.ToString()); + } + for (int i = 0; i < endLen; i++) + { + stream.Write(">"u8); + } + } } diff --git a/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/IpcClientTemplate.cs b/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/IpcClientTemplate.cs index 3faf8290e..79f790e7c 100644 --- a/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/IpcClientTemplate.cs +++ b/src/BD.Common8.SourceGenerator.Ipc.Client/Templates/IpcClientTemplate.cs @@ -263,6 +263,8 @@ void WriteMethodBodyWithWebApi() """u8, methodParas[0].ParaType); break; case MethodParametersCategory.GeneratorModelFromBody: + stream.Write(", "u8); + WriteTuple(stream, methodParas); break; } @@ -309,6 +311,59 @@ void WriteMethodBodyWithWebApi() } break; case MethodParametersCategory.GeneratorModelFromBody: + stream.Write( +""" +, global::System.TupleExtensions.ToTuple< +"""u8); + for (int i = 0; i < methodParas.Length; i++) + { + var (paraType, _, _) = methodParas[i]; + if (i == methodParas.Length - 1) + { + if (paraType.IsSystemThreadingCancellationToken) + { + break; + } + } + if (i != 0) + { + stream.Write( +""" +, +"""u8); + } + stream.WriteUtf16StrToUtf8OrCustom(paraType.ToString()); + } + stream.Write( +""" +>(( +"""u8); + for (int i = 0; i < methodParas.Length; i++) + { + var (paraType, paraName, _) = methodParas[i]; + if (i == methodParas.Length - 1) + { + if (paraType.IsSystemThreadingCancellationToken) + { + break; + } + } + if (i == 0) + { + stream.WriteUtf16StrToUtf8OrCustom(paraName); + } + else + { + stream.WriteFormat( +""" +, {0} +"""u8, paraName); + } + } + stream.Write( +""" +)), cancellationToken: cancellationToken +"""u8); break; } diff --git a/src/BD.Common8.SourceGenerator.Ipc.Server.Test/Program.cs b/src/BD.Common8.SourceGenerator.Ipc.Server.Test/Program.cs index 182c91f42..d996168d8 100644 --- a/src/BD.Common8.SourceGenerator.Ipc.Server.Test/Program.cs +++ b/src/BD.Common8.SourceGenerator.Ipc.Server.Test/Program.cs @@ -25,4 +25,22 @@ public Task SimpleTypes(bool p0, byte p1, sbyte p2, char p3, DateOnl { throw new NotImplementedException(); } + + Task ITodoService.Tuple(bool p0, byte p1, sbyte p2, char p3, DateOnly p4, DateTime p5, DateTimeOffset p6, decimal p7, double p8, ProcessorArchitecture[] p9, Guid p10, short p11, int p12, long p13, float p14, TimeOnly p15, TimeSpan p16, ushort p17, uint p18, ulong[] p19, Uri p20, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void OnMapGroup(IEndpointRouteBuilder endpoints) + { + var builder = endpoints.MapGroup("/ITodoService").RequireAuthorization(); + builder.MapGet("/All", (Delegate)(static async (HttpContext ctx) => await Ioc.Get().All(ctx.RequestAborted))); + builder.MapGet("/GetById/{id}", (Delegate)(static async (HttpContext ctx, [FromRoute] int id) => await Ioc.Get().GetById(id, ctx.RequestAborted))); + builder.MapGet("/SimpleTypes/{p0}/{p1}/{p2}/{p3}/{p4}/{p5}/{p6}/{p7}/{p8}/{p9}/{p10}/{p11}/{p12}/{p13}/{p14}/{p15}/{p16}/{p17}/{p18}/{p19}/{p20}/{p21}", (Delegate)(static async (HttpContext ctx, [FromRoute] bool p0, [FromRoute] byte p1, [FromRoute] sbyte p2, [FromRoute] char p3, [FromRoute] DateOnly p4, [FromRoute] DateTime p5, [FromRoute] DateTimeOffset p6, [FromRoute] decimal p7, [FromRoute] double p8, [FromRoute] ProcessorArchitecture p9, [FromRoute] Guid p10, [FromRoute] short p11, [FromRoute] int p12, [FromRoute] long p13, [FromRoute] float p14, [FromRoute] TimeOnly p15, [FromRoute] TimeSpan p16, [FromRoute] ushort p17, [FromRoute] uint p18, [FromRoute] ulong p19, [FromRoute] Uri p20, [FromRoute] Version p21) => await Ioc.Get().SimpleTypes(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, ctx.RequestAborted))); + builder.MapPost("/BodyTest", (Delegate)(static async (HttpContext ctx, [FromBody] Tuple body) => await Ioc.Get().BodyTest(todo, ctx.RequestAborted))); + builder.MapGet("/AsyncEnumerable/{len}", (Delegate)(static (HttpContext ctx, [FromRoute] int len) => Ioc.Get().AsyncEnumerable(len, ctx.RequestAborted))); + builder.MapPost("/Tuple", (Delegate)(static async (HttpContext ctx, [FromBody] Tuple>> body) => await Ioc.Get().Tuple(body.Item1, body.Item2, body.Item3, body.Item4, body.Item5, body.Item6, body.Item7, body.Rest.Item1, body.Rest.Item2, body.Rest.Item3, body.Rest.Item4, body.Rest.Item5, body.Rest.Item6, body.Rest.Item7, body.Rest.Rest.Item1, body.Rest.Rest.Item2, body.Rest.Rest.Item3, body.Rest.Rest.Item4, body.Rest.Rest.Item5, body.Rest.Rest.Item6, body.Rest.Rest.Item7, ctx.RequestAborted))); + } } \ No newline at end of file diff --git a/src/BD.Common8.SourceGenerator.Ipc.Server/Templates/IpcServerTemplate.cs b/src/BD.Common8.SourceGenerator.Ipc.Server/Templates/IpcServerTemplate.cs index b7cad3a47..e3864cce7 100644 --- a/src/BD.Common8.SourceGenerator.Ipc.Server/Templates/IpcServerTemplate.cs +++ b/src/BD.Common8.SourceGenerator.Ipc.Server/Templates/IpcServerTemplate.cs @@ -146,7 +146,6 @@ static void IEndpointRouteMapGroup.OnMapGroup(IEndpointRouteBuilder endpoints) } break; case MethodParametersCategory.FromBody: - case MethodParametersCategory.GeneratorModelFromBody: { var (paraType, paraName, _) = methodParas[0]; stream.WriteFormat( @@ -155,6 +154,19 @@ static void IEndpointRouteMapGroup.OnMapGroup(IEndpointRouteBuilder endpoints) """u8, paraType, paraName); } break; + case MethodParametersCategory.GeneratorModelFromBody: + { + stream.Write( +""" +, [FromBody] +"""u8); + WriteTuple(stream, methodParas); + stream.Write( +""" + body +"""u8); + } + break; } if (isAsyncEnumerableByReturnType) { @@ -199,13 +211,47 @@ static void IEndpointRouteMapGroup.OnMapGroup(IEndpointRouteBuilder endpoints) } break; case MethodParametersCategory.FromBody: - case MethodParametersCategory.GeneratorModelFromBody: { var (_, paraName, _) = methodParas[0]; stream.WriteUtf16StrToUtf8OrCustom(paraName); isFirstMapMethodArg = false; } break; + case MethodParametersCategory.GeneratorModelFromBody: + { + for (int i = 0; i < methodParas.Length; i++) + { + var (paraType, _, _) = methodParas[i]; + if (i == methodParas.Length - 1) + { + if (paraType.IsSystemThreadingCancellationToken) + { + break; + } + } + + // body.Item1, body.Item2, body.Item3, body.Item4, body.Item5, body.Item6, body.Item7, + // body.Rest.Item1, body.Rest.Item2, body.Rest.Item3, body.Rest.Item4, body.Rest.Item5, body.Rest.Item6, body.Rest.Item7, + // body.Rest.Rest.Item1, body.Rest.Rest.Item2, body.Rest.Rest.Item3, body.Rest.Rest.Item4 + if (i != 0) + { + stream.Write(", "u8); + } + + stream.Write("body"u8); + + var v = i / 7; + for (int j = 0; j < v; j++) + { + stream.Write(".Rest"u8); + } + stream.Write(".Item"u8); + + stream.WriteUtf16StrToUtf8OrCustom((i - (v * 7) + 1).ToString()); + } + isFirstMapMethodArg = false; + } + break; default: break; } diff --git a/src/BD.Common8.SourceGenerator.Shared/Helpers/TypeHelper.cs b/src/BD.Common8.SourceGenerator.Shared/Helpers/TypeHelper.cs index d8794b3da..2d8196528 100644 --- a/src/BD.Common8.SourceGenerator.Shared/Helpers/TypeHelper.cs +++ b/src/BD.Common8.SourceGenerator.Shared/Helpers/TypeHelper.cs @@ -22,7 +22,7 @@ public static bool IsSimpleTypes(this ITypeSymbol typeSymbol) if (typeSymbol.IsEnum()) return true; - switch (typeSymbol.ContainingNamespace.Name) + switch (typeSymbol.ContainingNamespace?.Name) { case "System": switch (typeSymbol.Name) diff --git a/src/Ipc.Server.Sample.Experimental/ITodoService.cs b/src/Ipc.Server.Sample.Experimental/ITodoService.cs index 4fe874b64..e7028b8d5 100644 --- a/src/Ipc.Server.Sample.Experimental/ITodoService.cs +++ b/src/Ipc.Server.Sample.Experimental/ITodoService.cs @@ -85,6 +85,41 @@ Task BodyTest(Todo todo, CancellationToken cancellationToken = defau /// /// IAsyncEnumerable AsyncEnumerable(int len, CancellationToken cancellationToken = default); + + /// + /// 测试使用 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task Tuple(bool p0, byte p1, sbyte p2, + char p3, DateOnly p4, DateTime p5, + DateTimeOffset p6, decimal p7, double p8, + ProcessorArchitecture[] p9, Guid p10, short p11, + int p12, long p13, float p14, + TimeOnly p15, TimeSpan p16, ushort p17, + uint p18, ulong[] p19, Uri p20, CancellationToken cancellationToken = default); } /// diff --git a/src/Ipc.Server.Sample.Experimental/Program.cs b/src/Ipc.Server.Sample.Experimental/Program.cs index 3df830ebe..cab2c054b 100644 --- a/src/Ipc.Server.Sample.Experimental/Program.cs +++ b/src/Ipc.Server.Sample.Experimental/Program.cs @@ -131,6 +131,12 @@ protected override void Configure(WebApplication app) app.UseSwagger(); app.UseSwaggerUI(); } + + // 测试元组 Tuple,System.Text.Json 不支持 ValueTuple + //var a = System.TupleExtensions.ToTuple((1, 2, 3)); + app.MapGroup("/Test") + .MapPost("Tuple", + (Delegate)(([FromBody] Tuple>> body) => body)); } } @@ -241,4 +247,18 @@ public async IAsyncEnumerable AsyncEnumerable(int len, [EnumeratorCancella yield return todos[^1]; // 超出长度返回最后一个 } } + + public async Task Tuple(bool p0, byte p1, sbyte p2, + char p3, DateOnly p4, DateTime p5, + DateTimeOffset p6, decimal p7, double p8, + ProcessorArchitecture[] p9, Guid p10, short p11, + int p12, long p13, float p14, + TimeOnly p15, TimeSpan p16, ushort p17, + uint p18, ulong[] p19, Uri p20, CancellationToken cancellationToken = default) + { + await Clients.All.SendAsync(nameof(ITodoService), nameof(SimpleTypes), RequestAborted()); + var result = ApiRspHelper.Ok(); + result.InternalMessage = $"{p0}/{p1}/{p2}/{p3}/{p4}/{p5}/{p6}/{p7}/{p8}/{string.Join(", ", p9 ?? [])}/{p10}/{p11}/{p12}/{p13}/{p14}/{p15}/{p16}/{p17}/{p18}/{string.Join(", ", p19 ?? [])}/{p20}"; + return result; + } } \ No newline at end of file