Search code examples
.net.net-assemblylayern-tier-architecture

How to get all assemblies in solution in .NET?


I have a typical 3-tier .NET application.

The Domain Layer does not reference the other projects.

The Data Access Layer references the Domain Layer and implements some repositories.

The Web View Layer consumes the Domain Layer's services and controls Autofac (IOC container).

The Domain and Data Access Layers implement Autofac modules. This means that from the Web View Layer, I can scan for all assemblies and register them with Autofac in order to provide dependency injection.

I do not want my Web View Layer to know about or care which Data Access Layer is used, so I do not want to include a reference to it. However, if I do not reference the Data Access Layer, the scan to find the assemblies will not pick it up.

Here is the startup method that is called in the Web View Layer:

private static void RegisterAutofacAssemblyModules(ContainerBuilder builder)
    {
        IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName.Contains("Boutique"));

        if (HostingEnvironment.InClientBuildManager)
        {
            assemblies = assemblies.Union(BuildManager.GetReferencedAssemblies().Cast<Assembly>()).Distinct();
        }

        builder.RegisterAssemblyModules(assemblies.ToArray());
    }

I added the .Where() to hopefully improve performance since less assemblies would have to be scanned. (Not sure if this is true or not).

And this code works perfectly fine if I reference the Data Access Layer (in the Web View Layer). But I do not want the Web View Layer to reference the Data Access Layer. So how can I scan the assembly to make sure the Data Access Layer is included? I would like to just get all the assemblies in the solution if possible.


Solution

  • It seems to me that you may be missing a Cross Cutting layer to deal with your IoC container registrations.

    Create a new class project named CrossCutting.IoC and move all Autofac registrations to it, except for the Web View Layer registrations, these will be handled by the Web Layer itself.

    So the Web Layer will have a reference to the IoC layer and will no longer need a reference to the Data layer. The IoC layer will have a reference to every other project.

    I use SimpleInjector, so I never implemented this in Autofac, but after a quick search it looks like you need to use Modules as explained in this answer. If you follow that answer's advice and create one module for each layer, then you can use RegisterAssemblyModules and register all modules at once.

    Edit

    I just tested this in a WebAPI project with the same layers as you plus the CrossCutting.IoC and it worked. According to the docs, you don't even have to use AppDomain, just the BuildManager:

    protected void Application_Start()
    {
        var builder = new ContainerBuilder();
    
        var config = GlobalConfiguration.Configuration;
    
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        builder.RegisterWebApiFilterProvider(config);
        builder.RegisterWebApiModelBinderProvider();
    
        // Automatically scan and register all modules found in referenced assemblies
        var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
        builder.RegisterAssemblyModules(assemblies);
    
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }
    

    I wouldn't configure it for runtime scanning though, I see it as a risk, I prefer to be explicit about it, so if you want, just replace the automatic scanning part with RegisterModule calls for each module:

    builder.RegisterModule<CrossCuttingModule>();
    builder.RegisterModule<DomainModule>();
    // etc...