Question

Ho do you register components with Autofac without referencing all the projects in your web application?

I have layered my application in the following format:

  • Website
  • Tasks
  • Services

Please use the code below for my explanations.

My controller class:

public class MyController : Controller
{
     private IMyTask myTask;

     public MyController(IMyTask myTask)
     {
          this.myTask = myTask;
     }

     public ActionResult Index()
     {
          HomeViewModel model = myTask.Index();

          return View(model);
     }
}

My task class:

public class MyTask : IMyTask
{
     private IMyService myService;

     public MyTask(IMyService myService)
     {
          this.myService = myService;
     }

     public HomeViewModel Index()
     {
          HomeViewModel homeViewModel = new HomeViewModel();

          // Do something with myService

          return homeViewModel;
     }
}

My Index action method would call a method from my task class, this would create my view model and return it to the action method.

I am only referencing the required references in each project, I don't want to reference any project that shouldn't be there. For example, my website will only reference MyProject.Tasks. And MyProject.Tasks will only reference MyProject.Services. My website will not contain references to both these projects.

I'm struggling to understand how I would use Autofac to register the above dependencies seeing that I don't reference both projects in my website?

Normally I would do it like this in Application_Start:

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterControllers(Assembly.GetExecutingAssembly());

builder.RegisterType<MyTask>().As<IMyTask>().InstancePerHttpRequest();
builder.RegisterType<MyService>().As<IMyService>().InstancePerHttpRequest();

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

I have tried this from my website:

builder.RegisterAssemblyTypes(Assembly.ReflectionOnlyLoad("MyProject.Services"))
     .Where(t => t.Name.EndsWith("Service"))
     .AsImplementedInterfaces();

...but it won't work because I did not reference MyProject.Services in the website.

What would be the best way to do this?

No correct solution

OTHER TIPS

I normally use external XML configuration file for registering (nearly) all the Autofac stuffs. It makes me more sense and introduces means like XML config transformations. It also avoids all unnecessary project references.

For example:

public static class AutofacConfig
{
    public static void Configure()
    {
        ContainerBuilder builder = new ContainerBuilder();

        ConfigurationBuilder config = new ConfigurationBuilder();
        config.AddXmlFile(@"Config\Autofac.config");

        IContainer container = builder.Build();

        AutofacServiceLocator serviceLocator = new AutofacServiceLocator(container);
        ServiceLocator.SetLocatorProvider(() => serviceLocator);
    }
}

For register components with Autofac without referencing all the projects in your web application do this:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var builder = new ContainerBuilder();
    var assemblies = GetAssembliesFromApplicationBaseDirectory(x => x.FullName.StartsWith("Your service name"));
    builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces();
    builder.Populate(services);
    return builder.Build();
}

private static Assembly[] GetAssembliesFromApplicationBaseDirectory(Func<AssemblyName, bool> condition)
{
    var baseDirectoryPath = AppDomain.CurrentDomain.BaseDirectory; // or directory with your dll
    Func<string, bool> isAssembly = file => string.Equals(Path.GetExtension(file), ".dll", StringComparison.OrdinalIgnoreCase);
    return Directory.GetFiles(baseDirectoryPath)
          .Where(isAssembly)
          .Where(f => condition(AssemblyName.GetAssemblyName(f)))
          .Select(Assembly.LoadFrom)
          .ToArray();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top