We have a dnx46 web project that uses startup at startup to register types. Our project.json dependencies include:
"Autofac.Configuration": "4.0.0-rc1-268", "Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177", "Autofac.Extras.CommonServiceLocator": "3.2.0", "Microsoft.AspNet.Hosting": "1.0.0-rc1-final", "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final", "Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-rc1-final", "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", "Microsoft.AspNet.Session": "1.0.0-rc1-final", "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", "Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc1-final", "Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final", "Microsoft.Extensions.Logging": "1.0.0-rc1-final", "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final", "Newtonsoft.Json": "8.0.3"
Our startup.cs ConfigureServices method is as follows:
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddSingleton(serviceType => Configuration); services.AddInstance<Microsoft.Extensions.Configuration.IConfiguration>(Configuration); services.AddCaching(); services.AddSession(); services.AddMvc(); var builder = new ContainerBuilder(); var assemblies = Directory.GetFiles(<ourBinDirectoryPath>, "*.dll", SearchOption.TopDirectoryOnly).Select(Assembly.LoadFrom); foreach (var assembly in assemblies) { builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository") || t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces(); builder.RegisterAssemblyTypes(assembly).Where(t => !t.Name.EndsWith("Service") && !t.Name.EndsWith("Repository") && !t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces().InstancePerDependency(); } builder.Populate(services); var container = builder.Build(); return container.Resolve<IServiceProvider>(); }
Our process is that we have several projects that we collect to remove these DLL files that this project will need in the user bin folder. At startup, we scan these assemblies to register types with Autofac. We did this to prove the conceptual design, and it worked without problems. However, in our new project, we have the following problems:
- If you try to enable the service in the controller constructor, this will throw an error indicating that the Microsoft Dependency injection cannot resolve the service. Not sure why he is not using the Autofac provider here.
- If we manually enable one type at startup along with our assembly scan, we get an error in the controller design indicating that Autofac was unable to enable this service (the Autofac provider is used here, but still cannot find our types).
- If I inspect the linker and container before it returns to ConfigureServices, it seems to register all of our types. However, if I change the controller to implement IServiceProvider, and then try to allow the service from it, it definitely uses the Autofac provider, but I always return null (no service was found).
After trying a lot of things, I took our proof of the draft concept and copied it to our new solution (if we missed some little tweaking or something when creating our new project), and the bad behavior continued. I'm starting to think that our assemblies introduce some errors (since these are the only things that changed after copying), but Autofac does not throw errors during scanning and instead simply does not use the types that it scanned correctly.
Change 1
I created and posted a very simplified example that reproduces the problem I am facing. You must remove this and run it to reproduce the error. You should receive an error message in the constructor of the main controller indicating that the service permission failed.
Note: when running this example, it launches a .bat file that puts the dll output from the domain project into your .nuget folder of your user profile.
Edit 2
Separate the interface into an abstraction folder based on @Travis Illig's recommendation. As soon as I did this, the solution got to work. We divided it into our "real" project, but it does not work. Still experiment to see why.
Edit 3
So finally, our project is working again. The problem ended with a few things:
- We had a project dependency on abstraction, indicated in our web project, and we also downloaded and looked at the DLLs from this assembly (double loading). (I think it was a big problem.)
- Our versions of NuGet were bad, so I donβt think they loaded correctly. We used 1.0.0-1, which is an invalid pre-format. Updated to 1.0.0-b1, and everything seemed to work better.
It took me more time to figure out, and my biggest problem at this point is that Autofac fails. I am very sorry that it will not explode and will not give me debugging information or something that indicates a problem. Instead, everything seemed to scan and load the fine, but then, when you went to use the container, it didn't solve anything.