diff --git a/src/Castle.Core.Tests/Core.Tests/Logging/DiagnosticsLoggerTestCase.cs b/src/Castle.Core.Tests/Core.Tests/Logging/DiagnosticsLoggerTestCase.cs
index 029c901be2..063c9ae5a8 100644
--- a/src/Castle.Core.Tests/Core.Tests/Logging/DiagnosticsLoggerTestCase.cs
+++ b/src/Castle.Core.Tests/Core.Tests/Logging/DiagnosticsLoggerTestCase.cs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if !NET9_0_OR_GREATER
+
namespace Castle.Core.Logging.Tests
{
using System;
@@ -101,3 +103,5 @@ public void SimpleUsage()
}
}
}
+
+#endif
diff --git a/src/Castle.Core/Castle.Core.csproj b/src/Castle.Core/Castle.Core.csproj
index fa705deaff..687288258a 100644
--- a/src/Castle.Core/Castle.Core.csproj
+++ b/src/Castle.Core/Castle.Core.csproj
@@ -3,7 +3,7 @@
- net8.0;net462;netstandard2.0
+ net9.0;net8.0;net462;netstandard2.0
diff --git a/src/Castle.Core/Core/Logging/DiagnosticsLogger.cs b/src/Castle.Core/Core/Logging/DiagnosticsLogger.cs
index bf591efc33..7674f44b11 100644
--- a/src/Castle.Core/Core/Logging/DiagnosticsLogger.cs
+++ b/src/Castle.Core/Core/Logging/DiagnosticsLogger.cs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if !NET9_0_OR_GREATER
+
namespace Castle.Core.Logging
{
using System;
@@ -147,3 +149,5 @@ private static EventLogEntryType TranslateLevel(LoggerLevel level)
}
}
}
+
+#endif
\ No newline at end of file
diff --git a/src/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs b/src/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs
index 97ee575e03..4deb0bdd2f 100644
--- a/src/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs
+++ b/src/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if !NET9_0_OR_GREATER
+
namespace Castle.Core.Logging
{
using System;
@@ -39,3 +41,5 @@ public override ILogger Create(string name, LoggerLevel level)
}
}
}
+
+#endif
diff --git a/src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs b/src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs
index 703e4aafb5..930c14d6a6 100644
--- a/src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs
+++ b/src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs
@@ -20,6 +20,11 @@ namespace Castle.DynamicProxy
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+#if NET9_0_OR_GREATER
+ using System.IO;
+ using System.Reflection.Emit;
+ using System.Runtime.Loader;
+#endif
using Castle.Core.Internal;
using Castle.Core.Logging;
@@ -30,9 +35,14 @@ namespace Castle.DynamicProxy
///
public class DefaultProxyBuilder : IProxyBuilder
{
- private readonly ModuleScope scope;
+ private ModuleScope scope;
private ILogger logger = NullLogger.Instance;
+#if NET9_0_OR_GREATER
+ protected ModuleScope lastScope;
+ protected MemoryStream lastAssemblyGenerated;
+#endif
+
///
/// Initializes a new instance of the class with new .
///
@@ -68,7 +78,7 @@ public Type CreateClassProxyType(Type classToProxy, Type[]? additionalInterfaces
AssertValidMixins(options, nameof(options));
var generator = new ClassProxyGenerator(scope, classToProxy, additionalInterfacesToProxy, options) { Logger = logger };
- return generator.GetProxyType();
+ return ToInstantiableType(generator.GetProxyType(), generator);
}
public Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[]? additionalInterfacesToProxy,
@@ -80,7 +90,7 @@ public Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[]? additional
var generator = new ClassProxyWithTargetGenerator(scope, classToProxy, additionalInterfacesToProxy, options)
{ Logger = logger };
- return generator.GetProxyType();
+ return ToInstantiableType(generator.GetProxyType(), generator);
}
public Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[]? additionalInterfacesToProxy,
@@ -92,7 +102,7 @@ public Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[]? ad
AssertValidMixins(options, nameof(options));
var generator = new InterfaceProxyWithTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, targetType, options) { Logger = logger };
- return generator.GetProxyType();
+ return ToInstantiableType(generator.GetProxyType(), generator);
}
public Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[]? additionalInterfacesToProxy,
@@ -103,7 +113,7 @@ public Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, T
AssertValidMixins(options, nameof(options));
var generator = new InterfaceProxyWithTargetInterfaceGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, interfaceToProxy, options) { Logger = logger };
- return generator.GetProxyType();
+ return ToInstantiableType(generator.GetProxyType(), generator);
}
public Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[]? additionalInterfacesToProxy,
@@ -114,7 +124,28 @@ public Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[]?
AssertValidMixins(options, nameof(options));
var generator = new InterfaceProxyWithoutTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, typeof(object), options) { Logger = logger };
- return generator.GetProxyType();
+ return ToInstantiableType(generator.GetProxyType(), generator);
+ }
+
+ private Type ToInstantiableType(Type type, BaseProxyGenerator generator)
+ {
+#if NET9_0_OR_GREATER
+ if (type.Assembly is PersistedAssemblyBuilder persistedAssemblyBuilder)
+ {
+ lastAssemblyGenerated?.Dispose();
+ var stream = new MemoryStream();
+ persistedAssemblyBuilder.Save(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+ var assembly = AssemblyLoadContext.Default.LoadFromStream(stream);
+ type = assembly.GetType(type.FullName!)!;
+ lastAssemblyGenerated = stream;
+ lastScope = scope;
+ scope = scope.Recycle();
+ }
+
+ generator.InitializeStaticFields(type);
+#endif
+ return type;
}
private void AssertValidMixins(ProxyGenerationOptions options, string paramName)
diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs
index 02f6012380..55df5d020d 100644
--- a/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs
+++ b/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs
@@ -102,7 +102,9 @@ protected sealed override Type GenerateType(string name, INamingScope namingScop
// Crosses fingers and build type
var proxyType = emitter.BuildType();
+#if !NET9_0_OR_GREATER
InitializeStaticFields(proxyType);
+#endif
return proxyType;
}
diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs
index 84e6b1186b..36823344bf 100644
--- a/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs
+++ b/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs
@@ -137,8 +137,9 @@ protected override Type GenerateType(string typeName, INamingScope namingScope)
// Crosses fingers and build type
var generatedType = emitter.BuildType();
-
+#if !NET9_0_OR_GREATER
InitializeStaticFields(generatedType);
+#endif
return generatedType;
}
diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs
index 2d790409d6..3fa9d993ce 100644
--- a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs
+++ b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs
@@ -384,7 +384,7 @@ protected void HandleExplicitlyPassedProxyTargetAccessor(ICollection targe
}
}
- protected void InitializeStaticFields(Type builtType)
+ internal void InitializeStaticFields(Type builtType)
{
builtType.SetStaticField("proxyGenerationOptions", BindingFlags.NonPublic, ProxyGenerationOptions);
}
diff --git a/src/Castle.Core/DynamicProxy/ModuleScope.cs b/src/Castle.Core/DynamicProxy/ModuleScope.cs
index af17ae2eb9..e84193b606 100644
--- a/src/Castle.Core/DynamicProxy/ModuleScope.cs
+++ b/src/Castle.Core/DynamicProxy/ModuleScope.cs
@@ -150,6 +150,13 @@ internal INamingScope NamingScope
internal SynchronizedDictionary TypeCache => typeCache;
+#if NET9_0_OR_GREATER
+ internal ModuleScope Recycle()
+ {
+ return new ModuleScope(savePhysicalAssembly, disableSignedModule, strongAssemblyName, strongModulePath, weakAssemblyName, weakModulePath);
+ }
+#endif
+
///
/// Gets the key pair used to sign the strong-named assembly generated by this .
///
@@ -336,6 +343,14 @@ private ModuleBuilder CreateModule(bool signStrongName)
return module;
}
else
+#elif NET9_0_OR_GREATER
+ if (savePhysicalAssembly)
+ {
+ AssemblyBuilder assemblyBuilder = new PersistedAssemblyBuilder(assemblyName, typeof(object).Assembly);
+ var module = assemblyBuilder.DefineDynamicModule(moduleName);
+ return module;
+ }
+ else
#endif
{
#if FEATURE_APPDOMAIN
@@ -368,7 +383,7 @@ private AssemblyName GetAssemblyName(bool signStrongName)
return assemblyName;
}
-#if FEATURE_ASSEMBLYBUILDER_SAVE
+#if FEATURE_ASSEMBLYBUILDER_SAVE || NET9_0_OR_GREATER
///
/// Saves the generated assembly with the name and directory information given when this instance was created (or with
/// the and current directory if none was given).
@@ -450,7 +465,11 @@ private AssemblyName GetAssemblyName(bool signStrongName)
}
assemblyBuilder = (AssemblyBuilder)StrongNamedModule.Assembly;
assemblyFileName = StrongNamedModuleName;
+#if NET9_0_OR_GREATER
+ assemblyFilePath = weakModulePath;
+#else
assemblyFilePath = StrongNamedModule.FullyQualifiedName;
+#endif
}
else
{
@@ -460,7 +479,11 @@ private AssemblyName GetAssemblyName(bool signStrongName)
}
assemblyBuilder = (AssemblyBuilder)WeakNamedModule.Assembly;
assemblyFileName = WeakNamedModuleName;
+#if NET9_0_OR_GREATER
+ assemblyFilePath = weakModulePath;
+#else
assemblyFilePath = WeakNamedModule.FullyQualifiedName;
+#endif
}
if (File.Exists(assemblyFilePath))
@@ -472,7 +495,12 @@ private AssemblyName GetAssemblyName(bool signStrongName)
AddCacheMappings(assemblyBuilder);
#endif
+#if FEATURE_ASSEMBLYBUILDER_SAVE
assemblyBuilder.Save(assemblyFileName);
+#elif NET9_0_OR_GREATER
+ var persistedAssemblyBuilder = (PersistedAssemblyBuilder)assemblyBuilder;
+ persistedAssemblyBuilder.Save(assemblyFilePath);
+#endif
return assemblyFilePath;
}
#endif
diff --git a/src/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs b/src/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs
index 4c591132de..bcd11f1c20 100644
--- a/src/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs
+++ b/src/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs
@@ -12,12 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#if FEATURE_ASSEMBLYBUILDER_SAVE
+#if FEATURE_ASSEMBLYBUILDER_SAVE || NET9_0_OR_GREATER
#nullable enable
namespace Castle.DynamicProxy
{
+#if NET9_0_OR_GREATER
+ using System.IO;
+#endif
+
///
/// ProxyBuilder that persists the generated type.
///
@@ -43,7 +47,17 @@ public PersistentProxyBuilder() : base(new ModuleScope(true))
///
public string? SaveAssembly()
{
+#if NET9_0_OR_GREATER
+ var assemblyPath = lastScope.WeakNamedModule != null ? lastScope.WeakNamedModuleName : lastScope.StrongNamedModuleName;
+ using var file = File.Create(assemblyPath);
+ lastAssemblyGenerated.Seek(0, SeekOrigin.Begin);
+ lastAssemblyGenerated.CopyTo(file);
+ file.Flush();
+ file.Close();
+ return assemblyPath;
+#else
return ModuleScope.SaveAssembly();
+#endif
}
}
}