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

Error when loading external assemblies #619

Open
sirosimo opened this issue Jul 19, 2022 · 2 comments
Open

Error when loading external assemblies #619

sirosimo opened this issue Jul 19, 2022 · 2 comments

Comments

@sirosimo
Copy link

sirosimo commented Jul 19, 2022

Working on an app migration form .Net Framework 4.8 to .Net 6, I'm facing an issue when trying to registered external assemblies from a certain folder.

container.Register(
        Classes.FromAssemblyInDirectory(new AssemblyFilter("Peoples"))
        .BasedOn<IPersonBase>()
        .WithServiceFromInterface() );

Here is an example project that highlight the issue: https://github.com/sirosimo/CastleSandBox.git

The external assemblies and classes implementing IPersonBase aren't referenced in the main application and may be in a different namespace.
In the framework version, this code work good, but when switching to .Net 6, I encounter FileNotFoundException when trying to load the assemblies.

Probable Cause:
I think I tracked down the issue to [Core.Internal.ReflectionUtil.cs line 136] (https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Core/Internal/ReflectionUtil.cs#:~:text=var%20assembly%20%3D%20LoadAssembly(assemblyName)%3B) and more precisely System.Reflection.Assembly

The assembly is loaded using the assembly name as opposed to the assembly file path. When using only the assembly name (Assembly.Load(assemblyName)) it results with a FileNotFoundException as the assembly name isn't referenced in the main application

Possible Solution:

Add an extra method to ReflectionUtil, using LoadFrom() instead of Load():

private static Assembly LoadAssembly(string assemblyFilePath){
return Assembly.LoadFrom(assemblyFilePath);
}

And change the way the assembly are being loaded to always refer to the filePath if available:

public static Assembly GetAssemblyNamed(string filePath, Predicate<AssemblyName> nameFilter, Predicate<Assembly> assemblyFilter){
var assemblyName = GetAssemblyName(filePath);
if (nameFilter != null)
	foreach (Predicate<AssemblyName> predicate in nameFilter.GetInvocationList())
		if (predicate(assemblyName) == false) return null;
				
var assembly = LoadAssembly(filePath);
if (assemblyFilter != null)
	foreach (Predicate<Assembly> predicate in assemblyFilter.GetInvocationList())
		if (predicate(assembly) == false) return null;

return assembly;
}

I tested it and it pass all the Castle.Windsor.Test

Thank you

Castle.Windsor 5.1.2
Castle.Core 4.1.1

@Jevonius
Copy link
Contributor

Jevonius commented Aug 4, 2022

Hey @sirosimo, sounds like a variant of dotnet/runtime#13511 - it appears to be a .Net Core issue rather than .Net 6 specifically from some brief Linqpad testing.

There might be some work to be done around FEATURE_ASSEMBLIES:

FEATURE_ASSEMBLIES - uses AssemblyName.GetAssemblyName() and Assembly.LoadFile().

For the .net standard build (which your .net 6 target will be using), FEATURE_ASSEMBLIES isn't set, but it seems for .net Core/5/6 it perhaps should be.

@Jevonius
Copy link
Contributor

Jevonius commented Aug 4, 2022

-- Edited out my wrong code :) --

There might be a similar issue with the method public static Assembly GetAssemblyNamed(string assemblyName) - looking at it, this is doing some form of detection for DLLs in the same folder as AppContext.BaseDirectory but that might need checking. There's two different code paths doing very similar things, but differently here, so would be nice to align them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants