diff --git a/global.json b/global.json index 1978c84..efae6fc 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "8.0.303" + "version": "8.0.421", + "rollForward": "latestFeature" } -} \ No newline at end of file +} diff --git a/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs b/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs index 8b14ddc..0d2f375 100644 --- a/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs +++ b/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs @@ -647,14 +647,14 @@ public class DefaultForwardFlow : IForwardFlow, ITransientDependency if (script.StartsWith("//async") || script.Contains("await")) { var @delegate = DelegateDic.GetOrAdd(scriptHash, - static (_, arg) => NDelegate.RandomDomain().AsyncFunc(arg), script); + static (_, arg) => NatashaScriptCompiler.CompileAsyncFunc(arg), script); await (Task)@delegate.DynamicInvoke(context)!; } else { var @delegate = DelegateDic.GetOrAdd(scriptHash, - static (_, arg) => NDelegate.RandomDomain().Action(arg), script); + static (_, arg) => NatashaScriptCompiler.CompileAction(arg), script); @delegate.DynamicInvoke(context); } } -} \ No newline at end of file +} diff --git a/src/InterfaceForward.Application/ForwardCore/NatashaScriptCompiler.cs b/src/InterfaceForward.Application/ForwardCore/NatashaScriptCompiler.cs new file mode 100644 index 0000000..f12505b --- /dev/null +++ b/src/InterfaceForward.Application/ForwardCore/NatashaScriptCompiler.cs @@ -0,0 +1,83 @@ +using System.Reflection; +using InterfaceForward.Application.Contracts.ForwardCore; +using Microsoft.CodeAnalysis; + +namespace InterfaceForward.Application.ForwardCore; + +internal static class NatashaScriptCompiler +{ + public static Action CompileAction(string script) + { + var method = Compile(script, "void"); + return method.CreateDelegate>(); + } + + public static Func CompileAsyncFunc(string script) + { + var method = Compile(script, "async System.Threading.Tasks.Task"); + return method.CreateDelegate>(); + } + + static MethodInfo Compile(string script, string returnType) + { + var typeName = "Script_" + Guid.NewGuid().ToString("N"); + var code = $$""" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using InterfaceForward.Application.Contracts.ForwardCore; + using InterfaceForward.Domain.Shared; + using InterfaceForward.Domain.Shared.Dtos; + using InterfaceForward.Domain.Shared.Enum; + using Newtonsoft.Json.Linq; + + public static class {{typeName}} + { + public static {{returnType}} Run(ForwardCoreContext obj) + { + var context = obj; + {{script}} + } + } + """; + + var assembly = new AssemblyCSharpBuilder() + .UseRandomDomain() + .WithSpecifiedReferences(GetMetadataReferences()) + .Add(code) + .GetAssembly(); + + return assembly + .GetType(typeName, throwOnError: true)! + .GetMethod("Run", BindingFlags.Public | BindingFlags.Static)!; + } + + static IEnumerable GetMetadataReferences() + { + var paths = new HashSet(StringComparer.OrdinalIgnoreCase); + + if (AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies) + { + foreach (var path in trustedPlatformAssemblies.Split(Path.PathSeparator)) + { + AddPath(path); + } + } + + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + AddPath(assembly.Location); + } + + return paths.Select(path => MetadataReference.CreateFromFile(path)); + + void AddPath(string? path) + { + if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) + { + paths.Add(path); + } + } + } +} diff --git a/src/InterfaceForward.Application/InterfaceForward.Application.csproj b/src/InterfaceForward.Application/InterfaceForward.Application.csproj index 6990b97..bf388ff 100644 --- a/src/InterfaceForward.Application/InterfaceForward.Application.csproj +++ b/src/InterfaceForward.Application/InterfaceForward.Application.csproj @@ -3,7 +3,7 @@ - net8 + net8.0 true @@ -16,7 +16,9 @@ - + + + diff --git a/src/InterfaceForward.Application/InterfaceForwardApplicationModule.cs b/src/InterfaceForward.Application/InterfaceForwardApplicationModule.cs index 1b135da..a6b774d 100644 --- a/src/InterfaceForward.Application/InterfaceForwardApplicationModule.cs +++ b/src/InterfaceForward.Application/InterfaceForwardApplicationModule.cs @@ -6,6 +6,8 @@ using Fake.ObjectMapping.AutoMapper; using Fake.RabbitMQ; using FreeRedis; using InterfaceForward.Application.Contracts; +using InterfaceForward.Application.Contracts.ForwardCore; +using InterfaceForward.Application.ForwardCore; using InterfaceForward.Application.Helpers; using InterfaceForward.Application.HostServices; using InterfaceForward.Domain.Shared; @@ -26,7 +28,7 @@ public class InterfaceForwardApplicationModule:FakeModule public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); - + context.Services.Configure(options => { options.ScanProfiles(); @@ -35,28 +37,49 @@ public class InterfaceForwardApplicationModule:FakeModule context.Services.Configure(configuration.GetSection("InterfaceRelay")); context.Services.AddHostedService(); - + var options = configuration.GetSection("Redis").Get(); if (options == null) throw new FakeException("未找到Redis相关配置,请检查配置文件中是否包含名为Redis的节点"); RedisHelper.Init(options, showLogInfo: System.Diagnostics.Debugger.IsAttached); - - // 预热 - NatashaInitializer.Preheating(); - - context.Services.AddHttpClient("forward", client => - { - client.Timeout = TimeSpan.FromSeconds(20); - }) + + // 预热并验证动态脚本编译环境。 + PreheatNatasha(); + + context.Services.AddHttpClient("forward", client => { client.Timeout = TimeSpan.FromSeconds(20); }) .ConfigurePrimaryHttpMessageHandler(_ => { var httpClientHandler = new HttpClientHandler(); // 确保支持较新的 SSL/TLS 版本 httpClientHandler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13; // 忽略 SSL/TLS 证书错误 - httpClientHandler.ServerCertificateCustomValidationCallback = + httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; return httpClientHandler; }); } -} \ No newline at end of file + + static void PreheatNatasha() + { + NatashaManagement.Preheating(false, false); + + var context = new ForwardCoreContext(); + NatashaScriptCompiler.CompileAction(""" + obj.FormFieldList.Add(new InterfaceForward.Domain.Shared.Dtos.InterfaceFormFieldDto + { + Name = "_natasha_health", + Value = obj.GetAccountFieldValueOrNull("_missing") ?? "ok" + }); + """)(context); + + NatashaScriptCompiler.CompileAsyncFunc(""" + //async + await System.Threading.Tasks.Task.CompletedTask; + obj.FormFieldList.Add(new InterfaceForward.Domain.Shared.Dtos.InterfaceFormFieldDto + { + Name = "_natasha_async_health", + Value = "ok" + }); + """)(context).GetAwaiter().GetResult(); + } +} diff --git a/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj b/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj index 7757a5e..3da43c3 100644 --- a/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj +++ b/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj @@ -3,7 +3,7 @@ - net8 + net8.0