From 58d8b30445d73c14a6762370554c1c0e93b9df21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=9C=A8=E6=A3=AE=20=C2=B7=20=E4=BD=9C=E9=9C=96?= <16236903+NMSAzulX@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:43:35 +0800 Subject: [PATCH] =?UTF-8?q?update=20compile=20=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=B9=E9=9D=9E=E5=85=AC=E6=88=90=E5=91=98=E7=9A=84=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WeatherForecastController.cs | 33 ++++++++++++ .../IgnoresAccessChecksToAttribute.cs | 0 .../HE/NET6.0/WebapiWIthController/Program.cs | 54 +++++++++++++++++++ .../WebapiWIthController/WeatherForecast.cs | 13 +++++ .../WebapiWIthController.csproj | 13 +++++ .../appsettings.Development.json | 8 +++ .../WebapiWIthController/appsettings.json | 9 ++++ .../NatashaSlimMethodBuilder.cs | 5 +- .../AssemblyCSharpBuilder.CompileOption.cs | 10 +++- .../AssemblyCSharpBuilder.Ouput.cs | 2 +- .../CompileUnit/AssemblyCSharpBuilder.cs | 25 +++++++++ .../Compiler/NatashaCSharpCompilerOptions.cs | 6 ++- .../Extension/NatashaStringExtension.cs | 1 + .../NatashaManagement.cs | 1 + .../Utils/NatashaAccessHelper.cs | 54 +++++++++++++++++++ 15 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 samples/HE/NET6.0/WebapiWIthController/Controllers/WeatherForecastController.cs rename {src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils => samples/HE/NET6.0/WebapiWIthController}/IgnoresAccessChecksToAttribute.cs (100%) create mode 100644 samples/HE/NET6.0/WebapiWIthController/Program.cs create mode 100644 samples/HE/NET6.0/WebapiWIthController/WeatherForecast.cs create mode 100644 samples/HE/NET6.0/WebapiWIthController/WebapiWIthController.csproj create mode 100644 samples/HE/NET6.0/WebapiWIthController/appsettings.Development.json create mode 100644 samples/HE/NET6.0/WebapiWIthController/appsettings.json create mode 100644 src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaAccessHelper.cs diff --git a/samples/HE/NET6.0/WebapiWIthController/Controllers/WeatherForecastController.cs b/samples/HE/NET6.0/WebapiWIthController/Controllers/WeatherForecastController.cs new file mode 100644 index 00000000..dcc0c8a9 --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace WebapiWIthController.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 _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/IgnoresAccessChecksToAttribute.cs b/samples/HE/NET6.0/WebapiWIthController/IgnoresAccessChecksToAttribute.cs similarity index 100% rename from src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/IgnoresAccessChecksToAttribute.cs rename to samples/HE/NET6.0/WebapiWIthController/IgnoresAccessChecksToAttribute.cs diff --git a/samples/HE/NET6.0/WebapiWIthController/Program.cs b/samples/HE/NET6.0/WebapiWIthController/Program.cs new file mode 100644 index 00000000..d5fc2c73 --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/Program.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; + +namespace WebapiWIthController +{ + public class Program + { + public static void Main(string[] args) + { + NatashaManagement.RegistDomainCreator(); + + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + + builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + var app = builder.Build(); + + + var action = @" +var modelMetadataProvider = arg1.Services.GetService(); +var controllerActivatorProvider = arg1.Services.GetService(); +((DefaultModelMetadataProvider)modelMetadataProvider).ClearCache(); +((DefaultControllerPropertyActivator)controllerActivatorProvider).ClearCache(); +Console.WriteLine(1111);" + .WithSlimMethodBuilder() + .WithMetadata(typeof(Console)) + .WithUsings("Microsoft.AspNetCore.Mvc.Controllers") + //.WithMetadata(typeof(IgnoresAccessChecksToAttribute)) + .WithMetadata(typeof(IModelMetadataProvider)) + .WithPrivateAccess(typeof(DefaultModelMetadataProvider)) + .ToAction()!; + action(app); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthorization(); + + + app.MapControllers(); + + app.Run(); + } + } +} diff --git a/samples/HE/NET6.0/WebapiWIthController/WeatherForecast.cs b/samples/HE/NET6.0/WebapiWIthController/WeatherForecast.cs new file mode 100644 index 00000000..b371c519 --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace WebapiWIthController +{ + 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; } + } +} diff --git a/samples/HE/NET6.0/WebapiWIthController/WebapiWIthController.csproj b/samples/HE/NET6.0/WebapiWIthController/WebapiWIthController.csproj new file mode 100644 index 00000000..2c33b1cd --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/WebapiWIthController.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/samples/HE/NET6.0/WebapiWIthController/appsettings.Development.json b/samples/HE/NET6.0/WebapiWIthController/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/HE/NET6.0/WebapiWIthController/appsettings.json b/samples/HE/NET6.0/WebapiWIthController/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/samples/HE/NET6.0/WebapiWIthController/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.MethodCreator/NatashaSlimMethodBuilder.cs b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.MethodCreator/NatashaSlimMethodBuilder.cs index 1ebdbcbc..97374b39 100644 --- a/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.MethodCreator/NatashaSlimMethodBuilder.cs +++ b/src/Natasha.CSharp/Extension/Natasha.CSharp.Extension.MethodCreator/NatashaSlimMethodBuilder.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Text; namespace Natasha.CSharp.Extension.MethodCreator { @@ -99,6 +97,7 @@ public T ToDelegate(string modifier = "") where T : Delegate var fullScript = $"{usingCode} public static class {className} {{ public static {(modifier ?? string.Empty)} {returnTypeScript} Invoke({parameterScript}){{ {Script} }} }}"; if (PrivateObjects!=null) { + Builder.WithPrivateAccess(); Builder.Add(fullScript.ToAccessPrivateTree(PrivateObjects)); } else diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs index c864b748..4ee971bb 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Natasha.CSharp.Compiler.Component; +using Natasha.CSharp.Compiler.Utils; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -45,7 +46,7 @@ public AssemblyCSharpBuilder ConfigCompilerOption(Action /// 链式对象(调用方法的实例本身). - public AssemblyCSharpBuilder WithPrivateMembers() + public AssemblyCSharpBuilder WithPrivateMembersOutput() { _includePrivateMembers = true; return this; @@ -57,7 +58,7 @@ public AssemblyCSharpBuilder WithPrivateMembers() /// 注:选项状态会被缓存,复用时无需重复调用. /// /// 链式对象(调用方法的实例本身). - public AssemblyCSharpBuilder WithoutPrivateMembers() + public AssemblyCSharpBuilder WithoutPrivateMembersOutput() { _includePrivateMembers = false; return this; @@ -172,6 +173,11 @@ public AssemblyCSharpBuilder WithReleasePlusCompile() public CSharpCompilation GetAvailableCompilation(Func? initOptionsFunc = null) { + if (_allowCompileWithPrivate) + { + NatashaAccessHelper.AccessHandle(this); + } + #if DEBUG Stopwatch stopwatch = new(); stopwatch.Start(); diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs index 94c28639..877c0f73 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs @@ -1,6 +1,7 @@ using Natasha.CSharp.Compiler.Utils; using System; using System.IO; +using System.Reflection; /// /// 程序集编译构建器-输出 @@ -20,7 +21,6 @@ public sealed partial class AssemblyCSharpBuilder public static readonly string GlobalOutputFolder; static AssemblyCSharpBuilder() { - GlobalOutputFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory!, "DynamicLibraryFolders"); if (!Directory.Exists(GlobalOutputFolder)) { diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs index 53eb16d2..c62562ea 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs @@ -1,4 +1,5 @@ using Natasha.CSharp.Compiler.SemanticAnalaysis; +using Natasha.CSharp.Compiler.Utils; using System; using System.Runtime.CompilerServices; @@ -11,6 +12,7 @@ [assembly: InternalsVisibleTo("Natasha.CSharp.UnitTest.Base, PublicKey=002400000480000094000000060200000024000052534131000400000100010069acb31dd0d9918441d6ed2b49cd67ae17d15fd6ded4ccd2f99b4a88df8cddacbf72d5897bb54f406b037688d99f482ff1c3088638b95364ef614f01c3f3f2a2a75889aa53286865463fb1803876056c8b98ec57f0b3cf2b1185de63d37041ba08f81ddba0dccf81efcdbdc912032e8d2b0efa21accc96206c386b574b9d9cb8")] public sealed partial class AssemblyCSharpBuilder { + private NatashaException? _exception; public NatashaException? GetException() @@ -42,6 +44,29 @@ public AssemblyCSharpBuilder(string assemblyName) } internal static bool HasInitialized; + + + private bool _allowCompileWithPrivate; + + /// + /// 该方法允许编译单元导入私有成员并进行编译 + /// + /// + public AssemblyCSharpBuilder WithPrivateAccess() + { + _allowCompileWithPrivate = true; + return this; + } + /// + /// 该方法不允许编译私有成员 + /// + /// + public AssemblyCSharpBuilder WithoutPrivateAccess() + { + _allowCompileWithPrivate = false; + return this; + } + /// /// 清空编译载体信息, 下次编译重组 Compilation . /// diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs index 6c9c671c..36e4a413 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs @@ -199,9 +199,13 @@ public NatashaCSharpCompilerOptions WithCompilerFlag(CompilerBinderFlags flags) /// public NatashaCSharpCompilerOptions AppendCompilerFlag(params CompilerBinderFlags[] flags) { + for (int i = 0; i < flags.Length; i++) { - _compileFlags |= flags[i]; + if (!_compileFlags.HasFlag(flags[i])) + { + _compileFlags |= flags[i]; + } } return this; } diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaStringExtension.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaStringExtension.cs index a7326eef..365c3c92 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaStringExtension.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaStringExtension.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Natasha.CSharp.Compiler.Utils; using System.Collections.Generic; +using System.Diagnostics; public static class NatashaStringExtension { diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/NatashaManagement.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/NatashaManagement.cs index b741aa6c..cfe2f228 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/NatashaManagement.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/NatashaManagement.cs @@ -6,6 +6,7 @@ public static partial class NatashaManagement { + public static NatashaInitializeHelper GetInitializer() { return new NatashaInitializeHelper(); diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaAccessHelper.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaAccessHelper.cs new file mode 100644 index 00000000..6d6c38b1 --- /dev/null +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Utils/NatashaAccessHelper.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Text; + +namespace Natasha.CSharp.Compiler.Utils +{ + public static class NatashaAccessHelper + { + public readonly static Action AccessHandle; + + static NatashaAccessHelper() + { + var accessType = Assembly.GetEntryAssembly().GetType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute", throwOnError: false); + if (accessType == null) + { + AssemblyCSharpBuilder builder = new(); + builder.UseDefaultLoadContext(); + builder.UseSimpleMode(); + builder.ConfigLoadContext(opt => opt + .AddReferenceAndUsingCode(typeof(object)) + .AddReferenceAndUsingCode(typeof(AssemblyName)) + ); + + builder.Add(@" +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class IgnoresAccessChecksToAttribute : Attribute + { + public IgnoresAccessChecksToAttribute(string assemblyName) + { + AssemblyName = assemblyName; + } + + public string AssemblyName { get; } + } +}"); + var assembly = builder.GetAssembly(); + accessType = assembly.GetTypeFromShortName("IgnoresAccessChecksToAttribute"); + } + + AccessHandle = builder => + builder + .ConfigCompilerOption(opt => opt + .WithAllMetadata() + .AppendCompilerFlag(CompilerBinderFlags.IgnoreAccessibility) + ) + .ConfigLoadContext(ctx => ctx.AddReferenceAndUsingCode(accessType)); + + } + } +}