Hi! I have to get all implementations (classes) of some interface. How I can do that? Now I only can to make it for current assembly (project), but the goal is to have it in separate project:
public T GetRepository
{
foreach (Type type in typeof(T).GetTypeInfo().Assembly.GetTypes())
if (typeof(T).IsAssignableFrom(type) && type.GetTypeInfo().IsClass)
return (T)Activator.CreateInstance(type);
return default(T);
}
The only idea we have is to parse json config files for dependencies and try to get that assemblies. But this looks to be strange.
I presume that this is for some sort of Add In model? Having a better idea of your use case is probably helpful.
As a side note: patterns like this are much harder (but not impossible!) to support in a world where you'd want to use .Net Native and our ahead of time compiler.
/cc @weshaggard @dsplaisted
We've always had problems in the past with this API where calling it too early would miss some types that were loadable but not loaded at the time of the call. In ASP.NET there was always BuildManager.GetReferencedAssemblies, that basically returned a list of all the assemblies (the entire closure) referenced by the application (including the application). That was a more accurate way to find things since it wouldn't miss the simple case where you had an application and a class library as a dependency, with the plugin defined in the class library but not loaded as yet.
It's also a pretty bad if you were forced to load all of the assemblies into the app domain eagerly. In the dnx, we came up with an API that would allow reasoning about the dependency graph of the application without eagerly loading all assemblies into memory. At the lowest level, it boils down to parsing JSON files :smile: but here's what it looks like (and is subject to change):
https://github.com/aspnet/dnx/blob/dev/src/Microsoft.Framework.Runtime.Abstractions/ILibraryManager.cs#L18
https://github.com/aspnet/dnx/blob/dev/src/Microsoft.Framework.Runtime.Abstractions/ILibraryManager.cs#L22
Here's how we use it in MVC:
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/DefaultAssemblyProvider.cs#L44
This API does make the assumption that the entire closure of loadable things ends up in the JSON file or is discovered on the startup path. Anything outside of that can be manually added (scanning directories for dlls and reading them using the new metadata reader API).
Thank you David, Matthew!
If I understand correctly, we are invited to rethink our discovery pattern.
Where we might once have filtered for _assemblies_ with _classes_ that implemented a particular _interface_, now we should consider filtering for _libraries_ that depend upon a particular _library_.
This is an auspicious approach even if it isn't exactly the same thing. We don't get the pinpoint targeting that assembly inspection affords. But it's great virtue is that assemblies don't have to be loaded.
The main burden is to structure the libraries so that they filter effectively - yet another reason to make small, focused libraries.
My problem (or task) is how to create modular website using asp.net 5. In the previous version (.NET 4.5) I used MEF for this. I had the main project (web application, container), which had Extensions folder. Inside that folder I could have any number of subfolder. One by extension. Each extension could have frontend and backend areas, views, dlls etc. Also, each extension could provide number of for example db implementations. To use concrete one you had to copy dll to the extension's Configuration file. So it was possible to add functions to the working web application without restarting and any configuration. Every extension provided implementation of IExtension interface which had all information about it (for example, backend menu structure). This is very common task and solution.
Now all of this is useless.
In order to use asp.net 5 with dnx core I'm facing the same problem, but I think that the solution should be different. Now we have dynamic compilation, now we publish source code to the server, now we can have project as dependency. So this question was the part of research and meditation. I don't know what to do with the views for now for example. How to have view in different projects etc etc etc
All of that can still work, you just have to know how to do it. For that particular feature (dropping DLLs into a folder and having them be loadable in the app domain), you can look at this sample:
https://github.com/aspnet/Entropy/blob/dev/samples/Runtime.CustomLoader/Program.cs
As for views/areas etc, you need to look at MVC's new extensibility points. I'd head over to the MVC repository for more ideas there.
I think that links to related SO question and Dmitry repository should be here
In this case I have one more sample (much bigger one):
https://github.com/Platformus/Platformus
It is platform for other modular projects.
Have the suggestions changed here? I'm porting a library to 5.4 and Microsoft.Dnx.Runtime 1.0.0-rc1-final isn't compatible there - it's dnxcore specific, not the new monikers, supporting that most of the functionality there is around Dnx specifics.
For the library loaded I need something that works across all of the netstandard platforms - is that planned? The specific library is StackExchange.Exceptional - our error logger which will run a great many places. The goal is to load other packages as valid error stores simply by including the package. e.g. if you also added StackExchange.Exceptional.MySQL to your project, that store is ready to use...and the core library knows nothing about it, it only contains the base classes the extension implements and is calling those members.
@NickCraver the functionality was separated from DNX: https://github.com/aspnet/PlatformAbstractions (also on NuGet).
Thanks henk - found what I needed there, much appreciated. For others tripping on this later, a verbose example:
C#
var libs = PlatformServices.Default.LibraryManager.GetReferencingLibraries("myLib")
.SelectMany(info => info.Assemblies)
.Select(info => Assembly.Load(new AssemblyName(info.Name)));
I would also recommend to look at DefaultAssemblyProvider from ASP.NET MVC and comments to https://github.com/dotnet/corefx/issues/1784
@davidfowl
We've always had problems in the past with this API where calling it too early would miss some types that were loadable but not loaded at the time of the call
Currently I'm in the process of porting FAKE to CoreCLR. We have a completely dynamic environment there and need the list of loaded assemblies for caching (https://github.com/fsharp/FAKE/blob/master/src/app/FakeLib/FSIHelper.fs#L396). What we do: We execute an F# script and afterwards store the compiled assembly on disk and alongside the list of all the assemblies that are loaded at the end of the execution (including their path and version). Next time we load everything at startup and execute the script (without compiling) when it wasn't modified.
I don't see any API helping with this right now in CoreCLR (looked at various proposed alternatives in various threads). I agree that the GetAssemblies()
is error prone. Do you have any idea how to tackle this?
@davidfowl : I just migrated to 1.0.0-rc2-final and noticed that PlatformServices.Default.LibraryManager.GetLibraries()
no longer works. What is the replacement for PlatformServices.Default.LibraryManager
?
+1
Also what is the replacement for IAssemblyLoader, IAssemblyLoadContext, IAssemblyLoaderContainer, IAssemblyLoadContextAccessor... ?
There is some info: https://github.com/aspnet/Announcements/issues/149
@DmitrySikorsky very useful reference, thanks a lot!
Where can PlatformServices.Default.LibraryManager
be found in .NET Core 1.0 RC2?
@6bee Take a look at my previous comment. Shortly: DependencyContext.Default.
When I use DependencyContext.Default to get a list of RuntimeLibraries, the Assemblies property is never populated. I'm attempting to enumerate all of the types associated with the loaded assemblies to find ones with a specific markup. From what I'm seeing, RuntimeLibrary and CompileLibrary are both useless for this as neither contains any information that would allow me to enumerate the classes associated with them. Is there something I'm missing here or is there another way to go about this?
Since DependencyContext is contained in Microsoft.Extensions.DependencyModel 1.0.0 it seams possible to target only .NETFramework 4.5.1 and .NETStandard 1.6. How can I do if I want to target .NET Core or Universal Windows Platform?
Each RuntimeLibrary in DependencyContext.Default.RuntimeLibraries contains a Version property but this is the version of the package and not the assembly. Has anyone worked out how to access the loaded assemblies and their versions yet?
Is there any view if/when RuntimeLibrary.Assemblies will be getting populated again (again since the aspnet/Announcements#149 sample output shows them populated at least for some of the packages)?
@rahku This is now supported for NC2.0, right?
AppDomain.GetAssemblies is now supported in NC2.0. Is that what you are looking for?
@gkhanna79 @rahku We also use AppDomain.GetAssemblies() in the Roslyn tests. In this case, we do it because may be trying to load different assemblies with the same MVID (like multiple versions of mscorlib) and we want to avoid bailing out iff the assembly was loaded before we started running tests.
In other words, our tests look something like
if (LoadedAssemblies.Contains(AssemblyToLoad.MVID) &&
!AlreadyLoaded.Contains(AssemblyToLoad))
{
throw Exception("Two modules have different MVID!");
}
And AlreadyLoaded
is built using AppDomain.GetAssemblies()
. I see that there's AssemblyLoadContext.GetLoadedAssemblies()
in master
, but I was hoping to write these tests to run on the shipped CoreCLR. Is there any way to figure out this information using .NET Core 1.1?
I think you can:
@jkotas Hmm not sure how that helps -- the constraint is that we only care if the MVIDs match if the assembly wasn't already loaded. We still need a mechanism to figure out whether or not the assembly was already loaded.
Could you please explain what you are trying to do on a bit more higher level? Are you planning to use multiple load contexts, or just the default load context?
.NET Core does not support loading multiple physical assemblies with the same name into a single load context. It is possible in desktop in some situations. Maybe this code just exists to handle this, and thus it is not applicable in .NET Core?
@jkotas The current code uses appdomains. The goal is to compile a series of programs against an arbitrary set of assemblies and run those compiled programs.
Of course, we may be compiling against multiple different assemblies with the same full identity, so the code tries to detect different assemblies by comparing MVIDs. If an MVID difference is found, we start up a new appdomain and load the set in the new appdomain.
The exception to the above is when the assembly is already loaded when we start running the tests (like with mscorlib). These assemblies won't be able to be reloaded, even if we start a new appdomain, so we ignore MVID differences for those assemblies.
the assembly is already loaded when we start running the tests
I do not think that it is the right set you want to filter. The currently loaded assemblies do not contain everything you want to filter. This set will be vary a lot over time - for example, even changes in JIT optimizations can add or remove assemblies in this set.
It is likely that mscorlib facade is not going to loaded when you start running tests (maybe not today - but it may happen tomorrow), but it is very likely that some of your tests are compiled against mscorlib and they won't work if you run them against the mscorlib (reference assembly?) that they are compiled against.
Instead, I think you should filter all platform assemblies - what comes with the test harness. System.AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")
will give you that list.
@jkotas Thanks, that sounds right. I'll give it a shot.
Is it actually impossible with the current RTM releases to enumerate all loaded assemblies (including assemblies loaded dynamically using AssemblyLoadContext
)?
Correct. The API was added back for .NET Core 2.0, but it does not change the fact that it should not be used in robust code - for the reasons I have mentioned above.
I don't want to use a specific API (and I don't see the point in reviving AppDomain
when application domains are not a thing anymore), I just want some API to enumerate loaded types.
What about DependencyContext.Default.GetDefaultAssemblyNames(); or GetRuntimeAssemblyNames("")?
This gives you a list of assmbly names which you can load and iterate over to get the loaded types.
DependencyContext
will only enumerate assemblies that were known at compile time, not the ones that were loaded dynamically. Nevertheless, it's more than nothing.
I've ran into the same darn issue. The method GetLoadedAssemblies() on AssemblyLoader would work but I'm not allowed to call it. All attempts to resolve the method fail either at compile time or at runtime.
@BalassaMarton Yes!
How get the all loaded dynamically?
Where get the assembly with code AssemblyLoadContext.Default.LoadFromAssemblyPath(path)
In https://github.com/fluentassertions/fluentassertions, I use this API to detect the test framework provider (MSTest, XUnit, MBUnit, etc) loaded in the current AppDomain. How would I do this with .NET Standard 1.3?
No good way to do it with .NET Standard 1.3.
No good way to do it with .NET Standard 1.3.
And higher versions? E.g. 1.6?
This API was added back in .NET Standard 2.0. None of .NET Standard 1.x has it.
I think this can be closed out with the milestone changed to 2.0 perhaps?
So there seems to be a myth on the internet that this was fixed in net core already. It is not. I got here specifically needing to deal with assemblies loaded at runtime. Oops.
@jhudsoncedaron Could you please create a new issue with details on what does not work for you?
The API in the title of this issue was added back in .NET Core 2.1. It works same as it always worked in .NET Framework.
Most helpful comment
When I use DependencyContext.Default to get a list of RuntimeLibraries, the Assemblies property is never populated. I'm attempting to enumerate all of the types associated with the loaded assemblies to find ones with a specific markup. From what I'm seeing, RuntimeLibrary and CompileLibrary are both useless for this as neither contains any information that would allow me to enumerate the classes associated with them. Is there something I'm missing here or is there another way to go about this?