Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -101,3 +103,5 @@ public void SimpleUsage()
}
}
}

#endif
2 changes: 1 addition & 1 deletion src/Castle.Core/Castle.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Import Project="..\..\buildscripts\common.props"></Import>

<PropertyGroup>
<TargetFrameworks>net8.0;net462;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;net462;netstandard2.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/Castle.Core/Core/Logging/DiagnosticsLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -147,3 +149,5 @@ private static EventLogEntryType TranslateLevel(LoggerLevel level)
}
}
}

#endif
4 changes: 4 additions & 0 deletions src/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -39,3 +41,5 @@ public override ILogger Create(string name, LoggerLevel level)
}
}
}

#endif
43 changes: 37 additions & 6 deletions src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if NET9_0_OR_GREATER
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using NET9_0_OR_GREATER we'd probably want a FEATURE_PERSISTEDASSEMBLYBUILDER conditional compilation symbol.

using System.IO;
using System.Reflection.Emit;
using System.Runtime.Loader;
#endif

using Castle.Core.Internal;
using Castle.Core.Logging;
Expand All @@ -30,9 +35,14 @@
/// </summary>
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

/// <summary>
/// Initializes a new instance of the <see cref = "DefaultProxyBuilder" /> class with new <see cref = "ModuleScope" />.
/// </summary>
Expand All @@ -45,7 +55,7 @@
/// Initializes a new instance of the <see cref = "DefaultProxyBuilder" /> class.
/// </summary>
/// <param name = "scope">The module scope for generated proxy types.</param>
public DefaultProxyBuilder(ModuleScope scope)

Check warning on line 58 in src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Non-nullable field 'lastAssemblyGenerated' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 58 in src/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Non-nullable field 'lastScope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
{
this.scope = scope;
}
Expand All @@ -68,7 +78,7 @@
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,
Expand All @@ -80,7 +90,7 @@

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,
Expand All @@ -92,7 +102,7 @@
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,
Expand All @@ -103,7 +113,7 @@
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,
Expand All @@ -114,7 +124,28 @@
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();
Comment on lines +135 to +143
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would likely have to be made thread-safe.

}

generator.InitializeStaticFields(type);
#endif
return type;
}

private void AssertValidMixins(ProxyGenerationOptions options, string paramName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +105 to +107
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be skipped here because the generated type cannot be activated while tied to a PersitedAssemblyBuilder.

return proxyType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ protected void HandleExplicitlyPassedProxyTargetAccessor(ICollection<Type> targe
}
}

protected void InitializeStaticFields(Type builtType)
internal void InitializeStaticFields(Type builtType)
{
builtType.SetStaticField("proxyGenerationOptions", BindingFlags.NonPublic, ProxyGenerationOptions);
}
Expand Down
30 changes: 29 additions & 1 deletion src/Castle.Core/DynamicProxy/ModuleScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ internal INamingScope NamingScope

internal SynchronizedDictionary<CacheKey, Type> TypeCache => typeCache;

#if NET9_0_OR_GREATER
internal ModuleScope Recycle()
{
return new ModuleScope(savePhysicalAssembly, disableSignedModule, strongAssemblyName, strongModulePath, weakAssemblyName, weakModulePath);
}
#endif

/// <summary>
/// Gets the key pair used to sign the strong-named assembly generated by this <see cref = "ModuleScope" />.
/// </summary>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -368,7 +383,7 @@ private AssemblyName GetAssemblyName(bool signStrongName)
return assemblyName;
}

#if FEATURE_ASSEMBLYBUILDER_SAVE
#if FEATURE_ASSEMBLYBUILDER_SAVE || NET9_0_OR_GREATER
/// <summary>
/// Saves the generated assembly with the name and directory information given when this <see cref = "ModuleScope" /> instance was created (or with
/// the <see cref = "DEFAULT_FILE_NAME" /> and current directory if none was given).
Expand Down Expand Up @@ -450,7 +465,11 @@ private AssemblyName GetAssemblyName(bool signStrongName)
}
assemblyBuilder = (AssemblyBuilder)StrongNamedModule.Assembly;
assemblyFileName = StrongNamedModuleName;
#if NET9_0_OR_GREATER
assemblyFilePath = weakModulePath;
#else
Comment on lines +468 to +470
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This alternative assignment may actually work also for .NET 4.6.2+, as [Weak|Strong]NamedModule.FullyQualifiedName is possibly equal to [weak|strong]ModulePath.

assemblyFilePath = StrongNamedModule.FullyQualifiedName;
#endif
}
else
{
Expand All @@ -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))
Expand All @@ -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);
Comment on lines +500 to +502
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is left-over code that (if it worked) would have to be called by the PersistentProxyBuilder on its lastScope. This code has been replaced with code directly in PersistentProxyBuilder however... probably not ideal.

#endif
return assemblyFilePath;
}
#endif
Expand Down
16 changes: 15 additions & 1 deletion src/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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

/// <summary>
/// ProxyBuilder that persists the generated type.
/// </summary>
Expand All @@ -43,7 +47,17 @@ public PersistentProxyBuilder() : base(new ModuleScope(true))
/// </remarks>
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;
Comment on lines +51 to +57
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should perhaps be replaced with return lastScope.SaveAssembly();.

#else
return ModuleScope.SaveAssembly();
#endif
}
}
}
Expand Down
Loading