Get list of loaded Assemblies on UAP10 platform - c#

On "normal" .NET assemblies targeting .NET Framework 4, I can use AppDomain.CurrentDomain.GetAssemblies() to get a list of all loaded assemblies.
How to do this on a Windows Universal App or on a CoreCLR application?

One way to kinda do what you want is to get the DLLs/assemblies which is located in the folder in which your app is installed (which one can assume in some cases is being used/loaded in your app).
public static async Task<List<Assembly>> GetAssemblyList()
{
List<Assembly> assemblies = new List<Assembly>();
var files = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFilesAsync();
if (files == null)
return assemblies;
foreach (var file in files.Where(file => file.FileType == ".dll" || file.FileType == ".exe"))
{
try
{
assemblies.Add(Assembly.Load(new AssemblyName(file.DisplayName)));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
return assemblies;
}
Then to loop through them you could do:
foreach (var assembly in GetAssemblyList().Result)
{
//Do something with it
}
Credits to this reddit thread/user.

How to do this on a Windows Universal App or on a CoreCLR application?
No, you can’t. Comparing with the Full.NET, the .NET for UWP only provides limited-level reflection functions.
In .NET for UWP, you can only get the assembly information by using the code below.
var assembly = this.GetType().GetTypeInfo().Assembly;

In our case, we can use AppDomain.CurrentDomain.GetAssemblies() which is in .NET Standard.
The only problem with this is that it won't find the assembly if the there are no direct code references to the project, even though there is a project reference. This was the case for us, as we use MEF to do things. To work around this, we just set up a dummy code reference.
I love "smart" compilers :)

Related

Why dynamically loaded .NET 6 plugins are no longer IsAssignableFrom the plugin interface when publishing with trim unused assemblies turned on?

I have created a small .NET 6 console application (GPU Offers on GitHub), which is using a plugin system to dynamically (at runtime) load plugins (DLL files).
When I dotnet publish the console app (not the plugins) with the option to trim unused assemblies, the plugins don't get recognized as a plugin by the console app anymore...
private static IEnumerable<IPluginInterface> CreatePlugins(Assembly assembly)
{
int count = 0;
foreach (Type type in assembly.GetTypes())
{
if (typeof(IPluginInterface).IsAssignableFrom(type))
{
IPluginInterface result = Activator.CreateInstance(type) as IPluginInterface;
if (result != null)
{
count++;
yield return result;
}
}
}
if (count == 0)
{
string availableTypes = string.Join(", ", Enumerable.Select(assembly.GetTypes(), t => t.FullName));
throw new ApplicationException(
$"Can't find any type which implements IPluginInterface in {assembly} from {assembly.Location}.\nAvailable types: {availableTypes}");
}
}
When I disable the trim unused assemblies option for the console application, the plugin is recognized again.
In my thought, the IPluginInterface cannot be treated as an "unused assembly", as it is actively used in the console application, as you can see above.
So, why the console application does not recognize the plugins anymore, when the trim unused assemblies publish option is enabled?

dotnet core get a list of loaded assemblies for dependency injection

I'm using AutoFac to automatically register dependencies based on their interface implementations like so:
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).AsImplementedInterfaces();
This works great for the entry assembly, but what about all of the related assemblies?
I'd like to do something like:
IList<Assembly> assemblies = GetLoadedAssemblies();
foreach(var assembly in assemblies)
{
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
}
I've searched and see a bunch of .netcore 1.0 stuff with AssemblyLoadContext, etc., but that no longer seems to exist in 1.1. Basically, when you search, you get lots of outdated references to stuff that no longer works.
There's got to be a way to get the currently loaded assemblies.
How can I do this?
In .NET Core 2.0 Lots of APIs were brought from .NET Framework, among them is AppDomain.CurrentDomain.GetAssemblies() which allows you to get the assemblies that have been loaded into the execution context of application domain. Of course the concept wasn't fully ported from .NET Framework to .NET Core so you can't create your own app domains and treat them as unit of isolation inside single process (so you only have one app domain). But this is enough for what you want to achieve.
You can use Scrutor which is working with .netstandard 1.6 or take a look how they're doing it here.
public IImplementationTypeSelector FromAssemblyDependencies(Assembly assembly)
{
Preconditions.NotNull(assembly, nameof(assembly));
var assemblies = new List<Assembly> { assembly };
try
{
var dependencyNames = assembly.GetReferencedAssemblies();
foreach (var dependencyName in dependencyNames)
{
try
{
// Try to load the referenced assembly...
assemblies.Add(Assembly.Load(dependencyName));
}
catch
{
// Failed to load assembly. Skip it.
}
}
return InternalFromAssemblies(assemblies);
}
catch
{
return InternalFromAssemblies(assemblies);
}
}
This is an old question , but none of the answers works for me.
I use autofac with asp.net core webapi project (.net 6).
This is where I need to get assemblies:
host
// autofac
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// autofac container
.ConfigureContainer<ContainerBuilder>(builder => {
// get assemblies for register
var assemblies = ???
builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces()...
});
The project is desinged by DDD, dependcies are like this:
webapi -> domain,infra
infra -> domain
For my situation:
AppDomain.CurrentDomain.GetAssemblies() can only get webapi assembly.
BTW: Assembly.GetEntryAssembly() can get the webapi assebmly too.
webapiAssembly.GetReferencedAssemblies() can only get domain project's assembly. Can't find the infra assembly.
Why GetReferencedAssemblies() doest not get all of the referenced assemblies as expected?
It's because in my project, webapi uses an repository interface, which is defines in domain, but implements in infra. Webapi project doesn't make any direct dependcy with infra layer (use class/interface defined in infra). So the infra assembly is not included.
If webapi has a directly dependcy with infra, use GetReferencedAssemblies() would be just fine.
Here is another solution that works for me:
Use DependencyContext which is inclued in Microsoft.Extensions.DependencyModel (nuget package) to get all assemblies that I wanted (webapi, domain, infra).
public static class AssemblyHelper
{
// get all assemblies that I wanted
// you may want to filter assemblies with a namespace start name
public static Assembly[] GetAllAssemblies(string namespaceStartName = "")
{
var ctx = DependencyContext.Default;
var names = ctx.RuntimeLibraries.SelectMany(rl => rl.GetDefaultAssemblyNames(ctx));
if (!string.IsNullOrWhiteSpace(namespaceStartName))
{
if (namespaceStartName.Substring(namespaceStartName.Length - 1, 1) != ".")
namespaceStartName += ".";
names = names.Where(x => x.FullName != null && x.FullName.StartsWith(namespaceStartName)).ToArray();
}
var assemblies = new List<Assembly>();
foreach (var name in names)
{
try
{
assemblies.Add(Assembly.Load(name));
}
catch { } // skip
}
return assemblies.ToArray();
}
}

How to load assembly correctly

I develop a system with plugins, which loads assemblies at runtime. I have a common interface library, which i share between server and its plugins. But, when i perform LoadFrom for plugin folder and try to find all types, which implement common interface IServerModule i get runtime exception:
The type 'ServerCore.IServerModule' exists in both 'ServerCore.dll'
and 'ServerCore.dll'
I load plugins like this:
foreach (var dll in dlls)
{
var assembly = Assembly.LoadFrom(dll);
var modules = assembly.GetExportedTypes().Where(
type => (typeof (IServerModule)).IsAssignableFrom(type)
&& !type.IsAbstract &&
!type.IsGenericTypeDefinition)
.Select(type => (IServerModule)Activator.CreateInstance(type));
result.AddRange(modules);
}
How can i deal with this trouble?
I'll be gratefull for any help
Inspect the problem DLL and its dependencies. Chances are good that it is pulling in ServerCore.dll from a different version of .NET than your main application.
I recommend you use MEF if you want to do plugins.
Well, my solution is ugly, but works and i'll go forward for MEF in future (maybe). For now, i added such thing:
if(Path.GetFileNameWithoutExtension(dll)==Assembly.GetCallingAssembly().GetName().Name)
continue;
Thanks everybody for awesome replies
EDIT: I came up to more elegant solution, here it is:
var frameworkAssemblies =
from file in new DirectoryInfo(frameworkDirectory).GetFiles()
where (file.Extension.ToLower() == ".dll" || file.Extension.ToLower() == ".exe")
&& !AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).Contains(file.GetFileNameWithoutExtension())
select Assembly.LoadFrom(file.FullName);

What is the 2013 way to load an assembly at runtime?

I want to load several assemblies at runtime from my plugin directory. The core app does not have references to the assemblies beforehand, the assemblies implement an interface given by the core app, thus have a reference to it. I found and article from 2005 explaining exactly what I need to do to make this work.
Currently I have this code, which is basically a LINQ'd version of what you find in the article above:
foreach (
IModule module in
Directory.EnumerateDirectories(string.Format(#"{0}/{1}", Application.StartupPath, ModulePath))
.Select(dir => Directory.GetFiles(dir, "*.dll"))
.SelectMany(files => files.Select(Assembly.LoadFrom)
.SelectMany(assembly => (from type in assembly.GetTypes()
where type.IsClass && !type.IsNotPublic
let interfaces = type.GetInterfaces()
where
((IList) interfaces).Contains(
typeof (IModule))
select
(IModule) Activator.CreateInstance(type))))
)
{
module.Core = this;
module.Initialize();
AddModule(module);
}
So what is the current way to dynamically load plugins/modules/assemblies at runtime?
You might want to look at Microsoft Managed Extensibility Framework also this Tutorial its kinda nice intro.
I'd suggest Managed Extensibility Framework
Alternatively, if you need to load "plugins" with no need to keep a reference, there is also PRISM
Doesn't the roslyn project provide with some helpful things?
http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx
http://www.developerfusion.com/article/143896/understanding-the-basics-of-roslyn/
var scriptEngine = new ScriptEngine();
var session = Session.Create();
scriptEngine.Execute("foo.dll", session);

Getting names of GAC Assemblies [duplicate]

Aloha
Given a plug-in architecture (C# / .NET 3.5) with the plug-ins stored in the GAC, how can I list/load all dll's that contain types that implement my specific interface? In other words, I'd like to investigate which plug-ins for my application are installed on a machine, by looking in the GAC.
-Edoode
To add to BFree's answer, I suggest that you could load the assemblies for reflection only. This gives you enhanced security (the assemblies aren't able to execute at all) without appdomains, and flexibility (you can load assemblies that are for a different architecture).
First a little clarification: a DLL cannot implement an interface. The DLL contains types that could implement a specific interface. Here's a .NET wrapper around fusion.dll that allows you to enumerate all the assemblies in the GAC. Once you have loaded the assembly with Assembly.Load you can try to find all the types that implement the specific interface:
foreach (var type in assembly.GetTypes())
{
var myInterfaceType = typeof(IMyInterface);
if (type != myInterfaceType && myInterfaceType.IsAssignableFrom(type))
{
Console.WriteLine("{0} implements IMyInterface", type);
}
}
The Gac is really just a directory on your machine like any other. Here's the typical breakdown:
c:\windows\assembly\GAC
\GAC_32
\GAC_MSIL
And maybe some others..
Within each of those folders, you'll find subfolders where the actual dll's are stored. You'll first need to write a recursive method to get you all the dll's found under \assembly\, (you can find these online easily if you're not comfortable doing it yourself). Once you have that list of dll's you can proceed to use Assembly.LoadFile to load up the assembly and check all the types to see if they implement a given interface.
My only suggestion would be to load up these dll's in a seperate appdomain so that you're not allowing any potential harmful dll's to get loaded into your app.
Some links:
Searching Directories.
Loading Assemblies and checking for a given interface.
Creating new AppDomain.
You should look at the Type Selector Tool in Enterprise Library. It's probably not what you want directly, but it does what you are describing and you might be able to borrow some implementation from it.
First off, I'd recommend not doing this. To do this, you have to load all the assemblies from the GAC. I'd recommend you have your user (or an admin, or whatever) tell you what assemblies to try to load from (though for that, you might want a list of all the options, which might be why you're asking this...)
That said, this might work, but it's throwing errors for several assemblies it should work for, and I'm not sure why.... Also, I'm not sure how to detect where the GAC is -- c:\windows\assembly is the default, but I don't know where the real value is stored (registry?)
var targetType = typeof(IComparable);
var errors = new List<Exception>();
var c = Directory.GetFiles(#"c:\windows\assembly", "*.dll", SearchOption.AllDirectories).ToList()
.ConvertAll(f => Path.GetFileNameWithoutExtension(f))
.Where(f => !f.EndsWith(".ni"))
.Distinct().ToList()
.ConvertAll(f => { try { return Assembly.ReflectionOnlyLoad(f); } catch (Exception ex) { errors.Add(ex); return null; } })
.Where(a => a != null)
.SelectMany(a => { try { return a.GetTypes(); } catch (Exception ex) { errors.Add(ex); return new Type[] { }; } })
.Where(t => targetType.IsAssignableFrom(t));
Good luck with that.

Categories

Resources