I am struggling to find a good answer on this.
I need to scan all the classes that implement an interface IDomainEvent
.
The problem is that those types are in projects that are not necessarily loaded. For example, if my main assembly is WebApi
, there is a dependency on Application
, which depends on Domain
, which depends on DomainEvents
therefore, I don't have an "easy" way to get all the types that implement IDomainEvent
and are in *DomainEvents.csproj
projects
Is there any nuget library that can dynamically navigate through all referenced projects/assemblies and its subdependencies and is able to retrieve all types implementing an interface?
It happens at startup once, so I'm not too concerned about performance.
PS: The following method returns 0, as expected, because the assemblies are not loaded
var allDomainEventTypes =
AppDomain
.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(t => t.IsAssignableTo(typeof(IDomainEvent)) && !t.IsInterface)
.ToList();
CodePudding user response:
You could possible try something along this lines
var definitions = typeof(YourTypeInsideAssembly).Assembly.GetImplementationsOf(typeof(IYourInterfaceType));
foreach (var definition in definitions)
{
//Do you thing with definition.
}
This would require to specify YourTypeInsideAssembly
for each implementation of the interface. E.G if you have one project which has 3 classes implementing the interface and another which has 4. You would need to specify two classes one for each project.
I think this way you are forcing to load the assembly as well.
P.S
This worked for me previously as well:
var allAssemblies = Assembly
.GetEntryAssembly()
.GetReferencedAssemblies()
.Select(Assembly.Load)
.ToArray();
CodePudding user response:
I haven't found anything nice. I've got the following workaround (thanks to this great article)
public static class AssemblyExtensions
{
public static IEnumerable<Assembly> GetAllAssemblies(this Assembly rootAssembly)
{
var returnAssemblies = new List<Assembly>();
var loadedAssemblies = new HashSet<string>();
var assembliesToCheck = new Queue<Assembly>();
assembliesToCheck.Enqueue(rootAssembly);
while (assembliesToCheck.Any())
{
var assemblyToCheck = assembliesToCheck.Dequeue();
foreach (var reference in assemblyToCheck.GetReferencedAssemblies())
{
var fullName = reference.FullName;
if (!loadedAssemblies.Contains(fullName))
{
var assembly = Assembly.Load(reference);
assembliesToCheck.Enqueue(assembly);
loadedAssemblies.Add(fullName);
returnAssemblies.Add(assembly);
}
}
}
return returnAssemblies;
}
}
It works well as it's capable of "recursively" loading referenced assemblies and therefore I can retrieve all types implementing the given interface.
However, notice that referencing a project does not necessarily mean that the assembly will be referenced if no class from that project is used.
var domainEventTypes =
typeof(Startup)
.Assembly
.GetAllAssemblies()
.SelectMany(x => x.GetTypes())
.Where(t => t.IsAssignableTo(typeof(IDomainEvent)))
.ToList();