Replies: 2 comments
-
It appears that |
Beta Was this translation helpful? Give feedback.
0 replies
-
I didn't have enough time to understand dotnet/orleans#236, and I will not have enough time to make a PR for this. What worked on my end was to provide the path to my preferred version of // --------------------------------
// Program.cs, replace existing method with this
// --------------------------------
private static void ResolveDependentAssemblies(
IDictionary<string, string> inputsMap,
string inputDir)
{
AssemblyResolver resolver = new AssemblyResolver(
assemblies: inputsMap,
folder: inputDir,
logger: log);
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += resolver.Resolve;
}
//---------------------------------
// AssemblyResolver.cs, new file
//---------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace MakeSfxCa
{
/// <summary>
/// The assembly resolver.
/// </summary>
public class AssemblyResolver
{
/// <summary>
/// The application folder (where we first look for assemblies).
/// </summary>
public string Folder { get; private set; }
/// <summary>
/// Instantiate an instance.
/// </summary>
/// <param name="assemblies">[NotNull]</param>
/// <param name="folder">The folder where we should search for assemblies first (if paths were not explicitly
/// given already).</param>
/// <param name="logger">[NotNull]</param>
public AssemblyResolver(
IDictionary<string, string> assemblies,
string folder,
TextWriter logger)
{
this.Folder = folder;
this.logger = logger;
foreach (KeyValuePair<string, string> entry in assemblies)
{
if (entry.Key.EndsWith(".dll") || entry.Key.EndsWith(".exe"))
{
AssemblyStub stub = new AssemblyStub(
assembly: null,
file: entry.Value);
this.assemblyCache[entry.Key] = stub;
}
}
}
/// <summary>
/// This is a <<see cref="ResolveEventHandler"/> intended to be hooked into the
/// <see cref="AppDomain.ReflectionOnlyAssemblyResolve"/> event.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="args">[NotNull] The event args.</param>
/// <returns>[NotNull] The assembly.</returns>
public Assembly Resolve(object sender, ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);
AssemblyStub stub = null;
if ( this.assemblyCache.TryGetValue($"{assemblyName.Name}.dll", out stub)
|| this.assemblyCache.TryGetValue($"{assemblyName.Name}.exe", out stub))
{
stub.EnsureLoaded();
if (stub.LoadError != null)
{
this.logger.WriteLine($" {stub.LoadError}");
}
}
else
{
stub = this.TryLoadUncachedAssembly(args.Name);
if (stub != null)
{
// Add it into the cache.
string key = Path.GetFileNameWithoutExtension(stub.File);
this.assemblyCache[key] = stub;
}
}
return stub?.Assembly;
}
/// <summary>
/// This is the cache of given assemblies. When a value has no <see cref="AssemblyStub.Assembly"/> then
/// it is just a stub for an assembly that has not been loaded yet.
/// Key = filename without path (e.g. "System.ValueTuple.dll")
/// Value.File = absolute filename with "dll" extension (e.g. "C:/Path/System.ValueTuple.dll")
/// </summary>
private Dictionary<string, AssemblyStub> assemblyCache = new Dictionary<string, AssemblyStub>();
/// <summary>
/// Logs are written here.
/// </summary>
private TextWriter logger;
/// <summary>
/// Tries to load an uncached assembly. This will not add the stub into the cache.
/// </summary>
/// <param name="asmName">The assembly name, as given by <see cref="ResolveEventArgs.Name"/>.</param>
/// <returns>If null, an assembly could not be found; otherwise this is the stub of the located assembly.</returns>
private AssemblyStub TryLoadUncachedAssembly(
string asmName)
{
AssemblyStub output = null;
AssemblyName assemblyName = new AssemblyName(asmName);
string tryPath = Path.Combine(this.Folder, $"{assemblyName.Name}.dll");
if (File.Exists(tryPath))
{
output = new AssemblyStub(
assembly: null,
file: tryPath);
}
else
{
tryPath = Path.Combine(this.Folder, $"{assemblyName.Name}.exe");
if (File.Exists(tryPath))
{
output = new AssemblyStub(
assembly: null,
file: tryPath);
}
}
if (output != null)
{
output.EnsureLoaded();
}
if (output?.Assembly == null)
{
Assembly asm = null;
try
{
asm = Assembly.ReflectionOnlyLoad(asmName);
}
catch (FileNotFoundException)
{
}
if (asm != null)
{
output = new AssemblyStub(
assembly: asm,
file: asm.Location);
if (asm.GetName().ToString() == assemblyName.ToString())
{
this.logger.WriteLine($" Loaded dependent assembly: {asm.Location}");
}
else
{
this.logger.WriteLine($" WARNING Loaded mismatched dependent assembly: {asm.Location}");
this.logger.WriteLine($" Loaded assembly: {asm.GetName()}");
this.logger.WriteLine($" Mismatched assembly: {assemblyName}");
}
}
}
if (output?.Assembly == null)
{
this.logger.WriteLine($" ERROR Dependent assembly not supplied: {assemblyName}");
if (output?.LoadError != null)
{
this.logger.WriteLine($" {output.LoadError}");
}
}
if (output?.File == null)
{
// Ensure that there is no stub if we do not have a file.
output = null;
}
return output;
}
}
}
//---------------------------------
// AssemblyStub.cs, new file
//---------------------------------
using System;
using System.IO;
using System.Reflection;
using System.Security;
namespace MakeSfxCa
{
/// <summary>
/// A stub that represents an assembly which may or may not be loaded yet.
/// </summary>
public class AssemblyStub
{
/// <summary>
/// The assembly (if loaded). If null, then the assembly has not been loaded yet.
/// </summary>
public Assembly Assembly { get; private set; }
/// <summary>
/// The absolute path to the assembly file.
/// </summary>
public string File { get; private set; }
/// <summary>
/// If defined, this is the error that occurred while trying to load the assembly. If null, an error was
/// not observed.
/// </summary>
public string LoadError { get; private set; }
public AssemblyStub()
{
}
/// <summary>
/// Constructs an instance.
/// </summary>
/// <param name="assembly"><see cref="Assembly"/></param>
/// <param name="file"><see cref="File"/></param>
public AssemblyStub(
Assembly assembly,
string file)
{
this.Assembly = assembly;
this.File = file;
}
/// <summary>
/// Ensures the assembly is loaded. This has no effect if the assembly is already loaded, or if an assembly
/// loading error was already detected. The load is only attempted once.
/// </summary>
public void EnsureLoaded()
{
if (this.Assembly != null || this.LoadError != null)
{
return;
}
try
{
this.Assembly = Assembly.ReflectionOnlyLoadFrom(this.File);
}
catch (Exception ex)
{
this.LoadError = $"Error: Failed to load dependent assembly: {this.File}. {ex.Message}";
}
}
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I am having a problem with the
MakeSfxCA.exe
tool: In our version of WiX (3.11.3.439) the tool doesn't support binding redirection. I can see that the problem still exists in the currentdevelop
branch by inspecting MakeSfxCA.ResolveDependentAssemblies.The scenario is:
.config
file.At runtime, the binding redirect loads
4.0.3.0
(which is what I want). Unfortunately, when I try to generate an assembly withMakeSfxCA.exe
I get the following error.This looks like a bug to me, but I wonder if there is an easy workaround. If not I will just rewrite MakeSfxCA.ResolveDependentAssemblies. In my case, I am already providing the path to
System.ValueTuple.dll
in theinputsMap
, so I can just create logic to select a value frominputMap
before falling back toAssembly.ReflectionOnlyLoad("System.ValueTuple")
;Beta Was this translation helpful? Give feedback.
All reactions