Home > Enterprise >  Nuget Library to get all types that implement an interface in all assemblies and referenced assembli
Nuget Library to get all types that implement an interface in all assemblies and referenced assembli

Time:10-21

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();
  • Related