Autofac AsImplementedInterfaces fails to resolve dependencies - asp.net-mvc

This is a big mystery for me. From time to time (can't find a pattern yet) autofac fail when tries to resolve dependencies, here's error message:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'IsThereAnyNews.Mvc.Controllers.HomeController' can be invoked with the available services and parameters:
Cannot resolve parameter 'IsThereAnyNews.DataAccess.IRssChannelsRepository rssRepository' of constructor 'Void .ctor(IsThereAnyNews.Services.IUserAuthentication, IsThereAnyNews.Services.ILoginService, IsThereAnyNews.Services.ISessionProvider, IsThereAnyNews.DataAccess.IRssChannelsRepository)'.
Here's how I wire the autofac
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetCallingAssembly());
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
// other registrations goes here
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
Project setup is done like this:
ASP.MVC
-> Interfaces (where needed)
-> Autofac
-> Interface
-> Implementations (*Repository, *Services)
Yet for some mystical (for me) reason my face is being slapped with this error. Can anyone explain it to me, what am I doing wrong
EDIT
Here's implementation of RssChannelsRepository
public class RssChannelsRepository : IRssChannelsRepository
{
private readonly ItanDatabaseContext database;
public RssChannelsRepository(ItanDatabaseContext database)
{
this.database = database;
}
}
Where ItanDatabaseContext is registered like this:
builder.RegisterType<ItanDatabaseContext>().InstancePerLifetimeScope();
Can't tell if stuff are loaded, currently Im facing that issue on azure. For me that happens when I do some debug session, change piece of code here-and-there and do incremental build. Then this issue appears, but not always. To solve it I simple run full rebuild and that's it.

The problem might be caused by the AppDomain.CurrentDomain.GetAssemblies() call. According to MSDN the method:
Gets the assemblies that have been loaded into the execution context of this application domain.
If an assembly isn't loaded yet, it won't be returned from the list. Since your bootstrap code runs very early during application startup, it is possible that no method has been JITted that statically depends on a type in the assembly that contains your repository. If this is the case, that assembly won't be loaded yet and won't be returned from the GetAssemblies() method causing the registration to be absent from Autofac.
To make sure that all assemblies are loaded in a deterministic way, you should call BuildManager.GetReferencedAssemblies(). For instance:
public static void RegisterDependencies()
{
BuildManager.GetReferencedAssemblies();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
// ...
}
It's even more efficient to use the assemblies returned from GetReferencedAssemblies as input for Autofac, since AppDomain.GetAssemblies() would return all System.* assemblies as well, which will cause Autofac to go through them as well. For instance:
public static void RegisterDependencies()
{
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
// ...
}
This all is described in more detail in the Autofac documentation.

Related

Autofac Fails to Resolve after App Pool Recycle

I've used Autofac for years and never seen this behavior: after building, the app runs fine. However, after the app pool is recycled (I tested this by touching the web.config), I get a DependencyResolutionException:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Namespace.Controllers.HomeController' can be invoked with the available services and parameters
HomeController has one dependency, which has other dependencies, etc. But I know it can resolve them, because it does before it's recycled. Why on earth would this happen???
I autowire everything like so:
public static IContainer GetAutoFacContainer()
{
var builder = new ContainerBuilder();
var assembliesToRegister = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.FullName.StartsWith("Prefix")).ToArray();
builder.RegisterAssemblyTypes(assembliesToRegister)
.AsImplementedInterfaces().AsSelf().PropertiesAutowired().InstancePerLifetimeScope();
return builder.Build();
}
Then I use the container for WebAPI and MVC Controllers.
var autoFacContainer = DependencyRegistrar.GetAutoFacContainer();
DependencyResolver.SetResolver(new AutofacDependencyResolver(autoFacContainer));
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(autoFacContainer);
Thanks to Steven's comment above, I did find the answer on the other question as well as the Autofac site. Why these never turned up in my research I don't know.
http://docs.autofac.org/en/latest/faq/iis-restart.html
The Solution
Change AppDomain.CurrentDomain.GetAssemblies()
To BuildManager.GetReferencedAssemblies().Cast<Assembly>()
Done!

AutoFac MVC Web API

I have a simple AutoFac example working but now want to apply this to my web api project AND have the correct separation between the layers.
The issue I am seeing is the standard controller x "does not have a default constructor" but i am stumped so asking for advice..
I am calling RegisterApiControllers as well as RegisterControllers..
this is what I have in my DependencyInjectionContainer
public static class DependencyInjectionContainer
{
public static ContainerBuilder Builder;
public static IContainer Container;
public static void Init(Assembly mainAssembly)
{
Builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
RegisterTypes(mainAssembly);
Container = Builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(Container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
private static void RegisterTypes(Assembly mainAssembly)
{
var roomBookingConnectionString = ConfigurationManager.ConnectionStrings["RoomBooking"].ConnectionString;
Builder.RegisterControllers(mainAssembly);
Builder.RegisterType<RoomRepository>().As<IRoomRepository>().WithParameter(new TypedParameter(typeof(string), roomBookingConnectionString));
Builder.RegisterType<RoomService>().As<IRoomService>();
Builder.RegisterApiControllers(mainAssembly);
Builder.RegisterFilterProvider();
}
}
I am calling this in my Global.asax.cs
DependencyInjectionContainer.Init(typeof(MvcApplication).Assembly);
One big assumption here is that this is correct...
Builder.RegisterApiControllers(mainAssembly);
edit---------------------------------------------------------------------
I have just tried moving all of the DI registrations etc in the 2 methods above back to the global.asax.cs and it works!?!?
I think its something to do with the 'RegisterApiControllers'. I am passing the calling assembly into the above init method using 'typeof(MvcApplication).Assembly'. Is there something wrong with this?
Thanks.
The RegisterApiControllers method is used by Autofac to locate the controllers.
When you do Builder.RegisterApiControllers(mainAssembly); are you sure the mainAssembly parameter is the assembly containing the controllers?
Anyway, if you have this kind of problems, you can do something like this (guessing you have a controller called RoomBookingController) :
builder.RegisterApiControllers(typeof(RoomBookingController).Assembly);
This way Autofac will locate the assembly containing your controller, no matter where it is.

Autofac Dependency Resolver ocasionally crash on controller resolving mvc 5 (DependencyResolutionException)

i have following problem, I have web application in mvc5 with autofac dependency injection and generic data repositories. Usually all is working fine, the web is runing with no error, but after some time online following error appear:
The dependency resolver is folowing:
public class IoCConfig {
public static IContainer BuildContainer < T > () {
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterApiControllers(typeof(T).Assembly);
builder.RegisterControllers(typeof(T).Assembly);
try {
foreach(var type in AssemblyLoader.Load < IDependency > ()) {
var registration = builder.RegisterType(type);
foreach(var interfaceType in type.GetInterfaces().Where(itf => typeof(IDependency).IsAssignableFrom(itf))) {
registration = registration.As(interfaceType);
if (typeof(IUnitOfWorkDependency).IsAssignableFrom(interfaceType)) {
registration = registration.InstancePerRequest();
}
}
}
} catch (Exception ex) {
throw ex;
}
return builder.Build();
}
}
and is executed on Application_Start.
The example constructor of the controller is:
[Authorize]
public class ClassesManagmentController: Controller {
IDepartmentsRepository _departmentRepo;
IClassesRepository _classesRepo;
IClassesCategoriesRepository _classesCategoriesRepo;
public ClassesManagmentController(IDepartmentsRepository departmentsRepo,
IClassesRepository classesRepo,
IClassesCategoriesRepository classesCatiegoriesRepo) {
_departmentRepo = departmentsRepo;
_classesRepo = classesRepo;
_classesCategoriesRepo = classesCatiegoriesRepo;
}
// the rest of the Controller code
}
And the example repo interface and class are:
public class ClassesCategoriesRepository: Bases.RepositoryBase < ClassesCategoryDto > , IClassesCategoriesRepository {
public ClassesCategoriesRepository(IContextFactory factory): base(factory) {
}
}
public interface IClassesCategoriesRepository: IGenericRepository < ClassesCategoryDto > , IDependency {}
The repositories are in dedicated project, the dependency resolver and identification interfaces (IDependency) are in dedicated project, and web is in one more project.
I checked already twice if all projects of my solution are referencing the same autofac and mvc libraries. i was trying different resolving types but i dont found solution yet.
Any help will be appreciated.
If things are working for a while and then stop working chances are IIS is recycling the app pool and your assembly scanning mechanism isn't picking up all the assemblies correctly. Per the documentation:
When hosting applications in IIS all assemblies are loaded into the AppDomain when the application first starts, but when the AppDomain is recycled by IIS the assemblies are then only loaded on demand.
To avoid this issue use the GetReferencedAssemblies() method on System.Web.Compilation.BuildManager to get a list of the referenced assemblies instead:
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
That will force the referenced assemblies to be loaded into the AppDomain immediately making them available for module scanning.
If this controller never works but everything else does, do a test in one of the working controllers - try to manually resolve the IDepartmentsRepository and see if you can. If you can, then... strange things are afoot. But if you can't, then it means that particular repo isn't being picked up by the scanning and isn't registered, so the exception is telling you exactly what's wrong.

Simple Injector manually registering controllers

I'm attempting to implement Dependency Injection into my architecture (MVC, DDD - Domain Model, Repository). And my architecture includes ASP.NET Identity 2.0.
At this stage, I don't want DI controlling any of the Identity 2.0 objects (UserAdminController, RolesAdminController...). I'd prefer the security objects outside of DI. At this stage, integrating the Identity objects in DI looks very difficult. I had a good look to see if someone has already done this, so I could read and learn how to do this. I couldn't find anything. (Found one post which came close, but no resolution).
Anyway, I've followed the Simple Injector MVC implementation (see standard code below), and trying many things, I believe the problem lies in me calling RegisterMvcControllers.
Correct me if I'm wrong, but this statement will pickup all controllers with their name post-fixed with "controller".
Question: How can I select which controllers get registered with Simple Injector? (Is this called manually registering?)
Any help would be greatly appreciated, as I've spent most of today trying to get my head around all this, and proceed to the next step, i.e. have DI implemented, and instantiating my objects.
...
...
... called from Application_Start()
// Create a Simple Injector container
var container = new Container();
// Configure the container
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// Verify the container's configuration
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
private static void InitializeContainer(Container container)
{
container.Register<MyService1>();
container.Register<IMyRepositoryA, MyRepositoryA>();
// Trying to include Identity into Simple Injector - please ignore
container.Register<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>(new ApplicationDbContext()));
}
The RegisterMvcControllers has the following constraints on the types it registers:
The type must be public
The type must implement System.Web.Mvc.IController
The type must not be abstract
The type must not be a generic type definition
Its name must end with "Controller"
You can see what happens here in the source code.
The RegisterMvcControllers extension method calls into the SimpleInjectorMvcExtensions.GetControllerTypesToRegister method to get the list of controllers to register. You can call that method yourself to see what is registered as follows:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
So instead of calling RegisterMvcControllers you can register the controllers yourself by calling the GetControllerTypesToRegister method:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly());
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
This way you can filter out any controller you want to register manually:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
.Where(type => type.Name != "UserStore`1");
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
Another option is to override the registration:
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Options.AllowOverridingRegistrations = true;
container.Register<IUserStore<ApplicationUser>>(
() => new UserStore<ApplicationUser>(new ApplicationDbContext()))
// Always set the option back to false ASAP to prevent configuration errors.
container.Options.AllowOverridingRegistrations = false;

Unity Interception using auto wiring

I got Unity interception working using a HadlerAttribute and an instance of ICallHandler. To get it working all I have to do is decorate the class with the [Trace] attribute, and the interceptor works great.
[Trace]
public interface IPersonService
{
string GetPerson();
}
However I would like to have interception working for all my methods in a couple of assemblies. So I am using Unity AutoRegistration to set up my container as follows:
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//container.AddNewExtension<UnityInterfaceInterceptionRegisterer>();
container.
ConfigureAutoRegistration().
ExcludeSystemAssemblies().
LoadAssemblyFrom(typeof(PersonService).Assembly.Location).
Include(If.ImplementsITypeName, Then.Register()).
ApplyAutoRegistration();
return container;
}
Works great, except when I attempt to setup global registration as per this post:
http://unity.codeplex.com/discussions/281022
I have a UnityContainerExtension configured as follows, where MVC4Unity is my DLL:
public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension
{
protected override void Initialize()
{
base.Container.AddNewExtension<Interception>();
base.Container.Configure<Interception>().
AddPolicy("LoggingPolicy").
AddMatchingRule<AssemblyMatchingRule>
(new InjectionConstructor("MVC4Unity")).
AddCallHandler(new TraceCallHandler());
base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);
}
private void OnRegister(object sender, RegisterEventArgs e)
{
IUnityContainer container = sender as IUnityContainer;
if (e != null && e.TypeFrom != null && e.TypeFrom.IsInterface)
{
container.Configure<Interception>()
.SetInterceptorFor(e.TypeFrom, e.Name, new InterfaceInterceptor());
}
}
}
Unfortunately it is always throwing a StackOverflowException (!) when it goes into the OnRegister method.
The question then is, has anyone implemented assembly or even namespace wide interception using Unity, and was this the way to go?
[EDIT]
It seems that no matter what I add in the AddMatchingRule line below, that the OnRegister handler is invoked for all included assemblies as well! ( for example even the Microsoft.* namespace assemblies!)
base.Container.AddNewExtension<Interception>();
base.Container.Configure<Interception>().
AddPolicy("LoggingPolicy").
// see what other types of matchings rules there are!
AddMatchingRule<NamespaceMatchingRule>
(new InjectionConstructor("MVC4Unity.*")).
AddCallHandler(new TraceCallHandler());
base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);
I'm late with my answer, but maybe someone will find this useful.
If I understood the problem correctly you need to apply one matching rule to multiple assemblies. For these kind of tasks you can use AssemblyMatchingRule (MSDN).
container.Configure<Interception>()
.AddPolicy("logging")
.AddMatchingRule<AssemblyMatchingRule>(
new InjectionConstructor(
new InjectionParameter("YourAssemblyName")))
.AddCallHandler<LoggingCallHandler>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(), new InjectionProperty("Order", 1));
In your last code snippet i think you need to remove dot asterisk in the end of namespace in order to add MVC4Unity namespace to your NamespaceMatchingRule.
For additional information please check this link - Policy Injection MSDN

Resources