Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add host option to disable AssemblyLoadContext #172

Merged
merged 1 commit into from
Jan 11, 2024
Merged
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 @@ -38,7 +38,7 @@ public Assembly LoadInAssemblyLoadContext (AssemblyLoadContext loadContext)
return loadContext.LoadFromStream (new MemoryStream (Assembly));
}
}
#else
#endif
public Assembly LoadInCurrentAppDomain ()
{
if (DebugSymbols != null) {
Expand All @@ -47,6 +47,5 @@ public Assembly LoadInCurrentAppDomain ()
return System.Reflection.Assembly.Load (Assembly);
}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,51 @@ namespace Mono.TextTemplating;

partial class CompiledTemplate
{
[SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "Same API for ALC and AppDomain build variants of the class")]
sealed class TemplateAssemblyContext : IDisposable
/// <summary>
/// Abstracts over loading assemblies into an AssemblyLoadContext or AppDomain
/// and resolving assemblies from the host.
/// </summary>
abstract class TemplateAssemblyContext : IDisposable
{
public abstract Assembly LoadAssemblyFile (string assemblyPath);
public abstract Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData);
public virtual void Dispose () { }

[SuppressMessage ("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Conditionally compiled version of this returns multiple concrete types")]

public static TemplateAssemblyContext Create (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
{
#if FEATURE_ASSEMBLY_LOAD_CONTEXT
if (!host.IsAssemblyLoadContextDisabled ()) {
return new AssemblyLoadContextTemplateAssemblyContext (host, referenceAssemblyFiles);
}
#endif
return new CurrentAppDomainTemplateAssemblyContext (host, referenceAssemblyFiles);
}
}

#if FEATURE_ASSEMBLY_LOAD_CONTEXT
sealed class AssemblyLoadContextTemplateAssemblyContext : TemplateAssemblyContext
{
readonly TemplateAssemblyLoadContext templateContext;
public TemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles) => templateContext = new (referenceAssemblyFiles, host);
public Assembly LoadAssemblyFile (string assemblyPath) => templateContext.LoadFromAssemblyPath (assemblyPath);
public Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInAssemblyLoadContext (templateContext);
public void Dispose () { }
#else
readonly CurrentDomainAssemblyResolver assemblyResolver;
public TemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles) => assemblyResolver = new (referenceAssemblyFiles, host.ResolveAssemblyReference);
public Assembly LoadAssemblyFile (string assemblyPath) => Assembly.LoadFile (assemblyPath);
public Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInCurrentAppDomain ();
public void Dispose () => assemblyResolver.Dispose ();
public AssemblyLoadContextTemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
=> templateContext = new (referenceAssemblyFiles, host);
public override Assembly LoadAssemblyFile (string assemblyPath) => templateContext.LoadFromAssemblyPath (assemblyPath);
public override Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInAssemblyLoadContext (templateContext);
}
#endif

sealed class CurrentAppDomainTemplateAssemblyContext : TemplateAssemblyContext
{
readonly CurrentDomainAssemblyResolver assemblyResolver;
public CurrentAppDomainTemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
=> assemblyResolver = new (referenceAssemblyFiles, host.ResolveAssemblyReference);
public override Assembly LoadAssemblyFile (string assemblyPath) => Assembly.LoadFile (assemblyPath);
public override Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInCurrentAppDomain ();
public override void Dispose ()
{
base.Dispose ();
assemblyResolver.Dispose ();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class TemplateProcessor : MarshalByRefObject
[SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "Needs to be an instance for MarshalByRefObject")]
public string CreateAndProcess (ITextTemplatingEngineHost host, CompiledAssemblyData templateAssemblyData, string templateAssemblyFile, string fullName, CultureInfo culture, string[] referencedAssemblyFiles)
{
using var context = new TemplateAssemblyContext (host, referencedAssemblyFiles);
using var context = TemplateAssemblyContext.Create (host, referencedAssemblyFiles);

Assembly assembly = templateAssemblyData is not null
? context.LoadInMemoryAssembly (templateAssemblyData)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if !FEATURE_ASSEMBLY_LOAD_CONTEXT

using System;
using System.IO;
using System.Reflection;
Expand Down Expand Up @@ -49,5 +47,3 @@ public void Dispose ()
}
}
}

#endif
16 changes: 16 additions & 0 deletions Mono.TextTemplating/Mono.TextTemplating/HostOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.VisualStudio.TextTemplating;

static class HostOptionExtensions
{
const string DisableAlcOptionName = "DisableAssemblyLoadContext";

static bool IsOptionTrue (this ITextTemplatingEngineHost host, string optionName) =>
host.GetHostOption(optionName) is string optionVal
&& (optionVal == "1" || optionVal.Equals("true", StringComparison.OrdinalIgnoreCase));

public static bool IsAssemblyLoadContextDisabled (this ITextTemplatingEngineHost host) => host.IsOptionTrue (DisableAlcOptionName);
}
Loading