AutoFac - InstancePerLifetimeScope becomes SingleInstance When Component Resolved as Dependency for Singleton - c#

Original:
Summary:
I'm having an issue with Autofac, where objects which are registered as singletons/'SingleInstance', are having their dependencies that are registered as 'InstancePerLifetimeScope' are ending up becoming 'singletons' after the resolution of the first singleton is resolved.
Details: I'm working on a project to incorporate Autofac (version #4.9.2) into a windows service which is responsible for running background tasks. In preparation I've tried reading everything I can that involves lifetime scopes. My code has Autofac resolve service objects, where each service has it's own expected role and function, and/or sometimes interact with other services (currently there are no circular dependencies). To do this I'm registering these services as Singletons and then resolving/starting each in a sequential order. By registering services as Singletons, if another service has an dependency on a already resolved service, rather then instantiate a new service Autofac returns the already resolved one.
The problem I'm running into is, there are instances where services have dependencies that when resolved it's expected that the dependency will be reused across the whole service (my example is a logger). However, it's also expected that the resolved dependency should be different in each service, as each service's resolved dependency could have different behavior. To do this I was registering these dependencies as 'InstancePerLifetimeScope'. However, when the service is resolved, the service's dependency which is registered as 'InstancePerLifetimeScope' end up in Autofac's root container which is retrieved for all other services that share the same dependency rather then resolving the dependency as a new object.
Example: I've placed an simplified example below that's similar to my code that replicates and outlines how the problem is being hit.
// Use of AutoFac with Established Components
var builder = new ContainerBuilder();
// Register
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope();
builder.RegisterType<Service>().Named<IService>("first").SingleInstance();
builder.RegisterType<Service>().Named<IService>("second").SingleInstance();
// Build
var container = builder.Build();
// Resolve
IService firstService = null;
using (ILifetimeScope firstScope = container.BeginLifetimeScope())
{
firstService = firstScope.ResolveNamed<IService>("first");
};
IService secondService = null;
using (ILifetimeScope secondScope = container.BeginLifetimeScope())
{
secondService = secondScope.ResolveNamed<IService>("second");
};
// Test
// This case is false, both services are different
if (firstService == secondService)
{
throw new Exception("Services were the same");
}
// This case is true, each service shares the same logger
if (((Service)firstService)._logger == ((Service)secondService)._logger)
{
throw new Exception("Loggers were the same");
}
public interface ILogger
{
void Log(string message);
}
public interface IService
{
void Run();
}
public class Logger : ILogger
{
public Logger()
{
Console.WriteLine("Create: Logger");
}
public void Log(string message)
{
Console.WriteLine(message);
}
}
public class Service : IService
{
public readonly ILogger _logger;
public Service(ILogger logger)
{
Console.WriteLine("Create: Service");
_logger = logger;
}
public void Run()
{
Console.WriteLine("Run");
}
}
Conclusion: I'd expect that when an object is registered as a 'InstancePerLifetimeScope', it would always be tied to the current child scope regardless of if the object it is being resolved for is registered as a 'SingleInstance'. However, instead it seems the resolved dependency is being placed in to the root scope.
Is there anything I can do to enforce 'InstancePerLifetimeScope' registration dependencies to be exactly that for objects that are resolved for a 'SingleInstance', so these dependencies don't end up in the root container and reused by other services?
Edit 08/05/2019:
From John King link which points to the subject of Captive Dependencies, I've reviewed the topic and agree that my issue falls into the realm of Captive Dependencies. However, I am surprised by how the matter is handled, in that captive dependencies just exists as a known issue across all IOC libraries, and there seems to be little to no hope of discussing different solutions to mitigate the issue within a update. Despite that I still think the problem I'm hitting is a bit different from the examples outlined in Autofac's documentation and the other resources which AutoFac references for how this issue can occur. My reasoning for this argument is that I believe the real problem here stems from "InstancePerLifetimeScope", so I'm wondering if this warrants the possibility of another solution.
The examples given by Autofac and the link to Mark Seemann blog post (Which is a good resource to understand captive dependency, just with a bad example), try to show a captive dependency for a singleton occurring which has an dependency that's registered as "Instance Per Dependency". The problem is that this example (shown below) is wrong in pointing out the actual problem. "ProductService" is registered as a singleton, so after it's resolved the first time it'll always return the same "ProductService" reference which the example implies is not the case.
Incorrect Example Linked by AutoFac Doc
// Example from https://blog.ploeh.dk/2014/06/02/captive-dependency/
var builder = new ContainerBuilder();
builder.RegisterType<ProductService>().SingleInstance();
builder.RegisterType<SqlProductRepository>().As<IProductRepository>();
builder.RegisterType<CommerceContext>();
var container = builder.Build();
var actual1 = container.Resolve<ProductService>();
var actual2 = container.Resolve<ProductService>();
// You'd want this assertion to pass, but it fails
Assert.NotEqual(actual1.Repository, actual2.Repository);
// Lightbarrier snippet: Ya but guess what this also fails
Assert.NotEqual(actual1, actual2);
From the above code it's implied that captive dependency can occur for an "Instance Per Dependency" registration however, as shown by the below example that's not the case.
Example of what's actually happening
var builder = new ContainerBuilder();
// Register
builder.RegisterType<Logger>().As<ILogger>(); // InstancePerDependency
builder.RegisterType<Test.Service.Service1>().As<IService1>().SingleInstance();
builder.RegisterType<Test.Service.Service2>().As<IService2>().SingleInstance();
// Build
var container = builder.Build();
// Resolve
IService1 firstService = container.Resolve<IService1>();
IService2 secondService = container.Resolve<IService2>();
// This is false in that "InstancePerDependency" didn't result in a Captive Dependency
if (((Test.Service.Service1)firstService)._logger == ((Test.Service.Service2)secondService)._logger)
{
throw new Exception("Loggers were the same");
}
What this means is that a captive dependency can only occur when you try register a class's lifetime to reside in the current scope it was resolved in or greater/parented scope.
What others have suggested is that just having your Singleton's dependencies be registered instance by dependency shouldn't make a big difference however, I think this is missing the whole point. There are cases where reusing the same dependency is important, I use the logger as a prime example where having multiple resolutions can lead to fighting over external resources like where data is being logged. What more, most of these captive dependency issues can be avoided simply by avoiding registering Singletons, as if your sharing within the child scopes you can at least close the child, but with singletons the dependency is captured in the root. And yet I would argue that these dependencies can be resolved as we desired without capture dependencies if we were to not use a IOC library like Autofac and pass them in manually ourselves, so logically it should be possible for AutoFac to do it if we can. However, I want Autofac to do the work for me and yet this is a huge trap to run into that I think most people should be aware of when they're looking at IOC libraries.
Question:
I've read that updating Autofac to resolve this issue for shared registered components would be difficult be difficult to program, but is it really that hard for Autofac to know the singleton's dependencies that are registered to be shared across the scope should reside on said current scope only, and not the root scope where the Singleton will reside? I would venture that when a Singleton instance is resolved, the instance's dependencies do not need to reside in the root scope in order for the singleton instance to exist, as they will exist in memory due to their reference in the singleton instance, thus there's no reason for the root scope to save these dependencies.
If this is really the case, the only path seems to be to never use the Singleton functionality within AutoFac and to find another way to work around it. That said I think there should be a huge warning about this problem in the Singleton portion of AutoFac's documentation which is currently missing.

Related

.NET Core Singleton Creation is called multiple times

I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.

How to allow for optional services with Microsoft.Extension.DependencyInjection?

I am playing around with ASP.NET Core on my own hobby project, I want to create a framework that will be consumed by a developer, and I want to allow optional service and use defaults if they are not registered.
I am getting the Unable to resolve service for type 'XXX' error, but I would prefer the DI to return null rather then throw an exception.
I want to allow for optional services, so if a service is found, use that in the constructor, if not found, pass null into the constructor.
In my implementation I have:
public IServiceManager(IService service, ...)
{
_service = service ?? new DefaultService();
...
}
So as you can see, if the service cannot be found (null) use the default.
Perhaps I am misunderstanding how DI works. Perhaps I could use a factory to do this instead?
However, in my system I using default services when non is provided will be a common occurrence, so I need a solution that doesn't require the consumer of the API to register a service.
Is there a way to configure ASP.NET Core DI to return null rather then throw an exception?
Add default value to that parameter in the constructor.
public IServiceManager(IService service = null, ...)
{
_service = service ?? new DefaultService();
...
}
By their very nature, constructor injection is always considered as mandatory.
The very first versions of the Microsoft DI (I don't like using the term ASP.NET Core DI, because it does not depend on ASP.NET Core and can be used outside of it) only supported the constructor with the most parameters.
I think this has been changed since then to allow multiple constructors and the IoC container will choose a fitting one. That being said, you'd likely need to define multiple constructors.
public IServiceManager(IService service, IOtherService otherService)
{
}
public IServiceManager(IOtherService otherService)
{
}
Then the second constructor should be called, if IService isn't registered with the IoC container.
But it's still quite a questionable practice at best and makes your code harder to maintain and hold its invariant/loose coupling.
You should never have to instantiate your types inside your services, not even for optional services.
Instead, you should provide registrations which allow a user to override them with their own implementations.
public static IServiceCollection AddMyLibrary(this IServiceCollection services)
{
services.TryAddTransient<IService, Service>();
services.TryAddTransient<IOtherService, OtherService>();
}
Then the user override it.
services.AddTransient<IService, CustomService>();
services.AddMyLibrary();
Now CustomService will be injected where IService is requested.
Easiest would be to register the DefaultService component itself for the IService service within your IoC container - I'm using the terminology of Castle Windsor. Most of the containers allow to register multiple components for a service. In case you do not register a custom component for the service (another implementation of IService), DefaultService will be resolved and injected; otherwise your custom component will be resolved for the service, just register the components in proper order (in Castle Windsor, the component registered first will be considered: multiple components for a service)
WindsorContainer container = new WindsorContainer();
container.Register(Component.For<IServiceManager>().ImplementedBy<ServiceManager>());
container.Register(Component.For<IService>().ImplementedBy<CustomService>());
container.Register(Component.For<IService>().ImplementedBy<DefaultService>());
IServiceManager serviceManager = container.Resolve<IServiceManager>();
IService service = ((ServiceManager)serviceManager).Service; // service is of type CustomService
Regarding the comment below from #Tseng:
This beats the idea of having Dependency Injection / IoC container in the firstplace, when you instantiate it inside the constructor
It is not always the case... If you have an optional dependency, first, define it as a property with a public setter, so component can be injected if registered. In case there is no component registered (thus property is not set by the container), I think it can be acceptable to instantiate the default component via the "dangerous" new keyword. Everything is context-dependent - to be clear, I wouldn't instantiate a service manually, but there are always exceptions.

How to use Autofac to resolve instance per request dependencies for types in a child lifetime scope created by Nancy

We have several applications hosted in Windows services that self host a Nancy endpoint in order to expose instrumentation about the operation of the applications.
We use Autofac as our IOC. Several repositories are registered into the root container in a core DLL shared by all applications; this container is then passed to Nancy as its container using a bootstrapper derived from the Nancy.Autofac.Bootstrapper.
What we found was that when a web request is received by Nancy it resolves a request for a repository from the root container and this led to memory being consumed by non-garbage collected IDisposables as the root container does not go out of scope (it has the lifetime of the windows service). This led to the services "leaking" memory.
We then switched to a model where we added registrations for the repositories using InstancePerRequest in the overridden ConfigureRequestContainer() method in our Nancy bootstrapper:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
PerRequestContainerBuilder().Update(container.ComponentRegistry);
}
private static ContainerBuilder PerRequestContainerBuilder()
{
var builder = new ContainerBuilder();
// Dependency for repository
builder.RegisterType<SystemDateTimeProvider>().InstancePerRequest().As<IDateTimeProvider>();
// Repository
builder.RegisterType<BookmarkRepository>().InstancePerRequest().As<IBookmarkRepository>();
return builder;
}
We also override the CreateRequestContainer() method to create the request container with the tag MatchingScopeLifetimeTags.RequestLifetimeScopeTag.
protected override ILifetimeScope CreateRequestContainer(NancyContext context)
{
return ApplicationContainer.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}
This appears to have solved the problem of IDisposables not being disposed - the child request container is disposed at the end of the web request pipeline and objects resolved by it are also disposed and eventually garbage collected.
Our problem is that this seems to be leaking the implementation details of the repositories into the services as we have to not only register the repository in ConfigureRequestContainer() but also any other objects required by the repository, i.e. if we want to change the implementation of a repository we have to "walk the dependency chain" to register required objects in each service using it - this seems wrong.
Is there a way we can get Autofac to resolve supporting objects for the repositories out of the root container but keep the registration information within the scope of the web request container? Or is there a way to automatically copy existing registrations from the root container into the child container when it is created?
Autofac should automatically resolve instances from "parent" lifetimes. If you configure your registrations using InstancePerRequest, Autofac will register these services with a special lifetime tag, MatchingScopeLifetimeTags.RequestLifetimeScopeTag, so it can be resolved in the correct scope later.
This means that there's no need to use the Nancy bootstrapper's ConfigureRequestContainer method to do request-scoped registrations. You've already done it! As long as Nancy creates the request lifetime using the same tag used in InstancePerRequest (this is done by default as of Nancy 1.1), the services should be resolved correctly.
Example:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// Do request-scoped registrations using InstancePerRequest...
var container = builder.Build();
// Pass the pre-built container to the bootstrapper
var bootstrapper = new MyAwesomeNancyBootstrapper(container);
app.UseNancy(options => options.Bootstrapper = bootstrapper);
}
}
public class MyAwesomeNancyBootstrapper : AutofacNancyBootstrapper
{
private readonly ILifetimeScope _lifetimeScope;
public MyAwesomeNancyBootstrapper(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
protected override ILifetimeScope GetApplicationContainer()
{
return _lifetimeScope; // Tell Nancy you've got a container ready to go ;)
}
}
This setup should be enough (As of Nancy 1.1. In earlier versions you have to also override the CreateRequestContainer method and pass the request lifetime tag when creating the request lifetime scope).
EDIT: I put together an example for you at https://github.com/khellang/Nancy.AutofacExample

Get the container instance for Simple Injector

I am using Simple Injector with a ASP.NET MVC project. I added the SimpleInjector.Integration.Web.Mvc nuget package. This adds SimpleInjectorInitializer class in App_Start folder and initializes the DI. The code looks something like
public static void Initialize()
{
// Did you know the container can diagnose your configuration?
// Go to: https://simpleinjector.org/diagnostics
var container = new Container();
//Container configuration code
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
This configures the DI for the MVC controller correctly.
My question is, if I want to get the instance of the container in any of the controller\class to resolve some dependency manually how can I do it.
I have earlier worked on AutoFac and it has a dependency interface IComponentContext which can be injected into any class that needs to do any resolution manually.
Update:
Here is a scenario. My controller uses a service who initialization depends upon the input parameter passed in the controller method and hence the dependency cannot be instantiated during construction time.
I understand that this is somewhat an anti pattern for DI, but it is requirement at few places and hence injecting the DI container is next best thing. Simple Injector samples should use of static variable to share the container which i want to avoid and also it is not possible by the way SimpleInjectorInitializer works.
Except for any code that is part of the startup path of the application, no code should depend directly on the container (or a container abstraction, container facade, etc). This pattern is called Service Locator and Mark Seemann has a good explanation why this is a bad idea.
So components (such as Controllers) should not depend on the container directly, since this hides the used dependencies and makes classes harder to test. Furthermore your code starts to depend on an external framework (making it harder to change) or depending on an abstraction it doesn't need to know about.
My controller uses a service who initialization depends upon the input
parameter passed in the controller method and hence the dependency
cannot be instantiated during construction time
There's a general pattern for this problem: the abstract factory design pattern. The factory pattern allows you to delay the creation of types and allows you to pass in extra runtime parameters for the construction of a certain type. When you do this, your controller doesn't have to depend on Container and it prevents you from having to pass in a constructed container in your unit tests (DI frameworks should in general not be used in your unit test projects).
Do note however that letting your components require runtime data during creation is a code smell. Prevent doing that.
You might think that by doing this we are just moving the problem to the factory implementation. Although we are moving the dependency on the container into the factory implementation, we are in fact solving the problem because the factory implementation will be part of the application's Composition Root, which allows the application code itself oblivious to any DI framework.
So this is how I advice you to structure your code:
// Definition of the factory in the UI or BL layer
public interface ISomeServiceFactory
{
ISomeService Create(int inputParameter);
}
// Controller depending on that factory:
public class MyController : Controller
{
private readonly ISomeServiceFactory factory;
public MyController(ISomeServiceFactory factory)
{
this.factory = factory;
}
public ActionResult Index(int value)
{
// here we use that factory
var service = this.factory.Create(value);
}
}
In your composition root (the start up path) we define the factory implementation and the registration for it:
private class SomeServiceFactory : ISomeServiceFactory
{
private readonly Container container;
// Here we depend on Container, which is fine, since
// we're inside the composition root. The rest of the
// application knows nothing about a DI framework.
public SomeServiceFactory(Container container)
{
this.container = container;
}
public ISomeService Create(int inputParameter)
{
// Do what ever we need to do here. For instance:
if (inputParameter == 0)
return this.container.GetInstance<Service1>();
else
return this.container.GetInstance<Service2>();
}
}
public static void Initialize()
{
var container = new Container();
container.RegisterSingle<ISomeServiceFactory, SomeServiceFactory>();
}
Upon creation, the Container registers itself (using the call RegisterSingle<Container>(this)) so you can always inject the container into any component. That's similar to injecting the IComponentContext when working with Autofac. But the same holds for Autofac, Simple Injector, and any other container: you don't want to inject your container into components that are located outside the composition root (and there hardly ever is a reason for it).

Should creating a Unity Container be considered an expensive operation as it relates to resources and time?

I've recently started using Unity for dependency injections in .net.
I was under the impression that a Unity Container would most likely be a singleton or static member of a class. I saw another developer using it in a request handler that will receive a lot of traffic.
Is there some magic happening that keeps the cost low for creating a new Unity Container every time, or should this code be re-factored to only create the Unity container once?
This code is part of the implementing class of a .svc Service.
public string DoSomeWork(Request request)
{
var container = new UnityContainer().LoadConfiguration("MyContainer");
var handler = container.Resolve<RequestHandler>();
return handler.Handle(request);
}
Not 100% sure with Unity, but with most IoC containers, the creation of the container and especially the loading of container configuration is a reasonably expensive operation.
I have to question why this developer is utilizing the container in this manner however. Ideally the IoC container shouldn't even be a static or singleton object - it should be instantiated only to resolve the top level object of your dependency tree, and the rest of the objects in your application should be constructed automatically through dependency injection. In the case of your example, the class containing that method ideally would have the RequestHandler (ideally an interface of this) injected into it through the constructor so that class does not need to know about the IoC container.
This is not the right way to use an IOC container - basically your are using it as a service locator, but this will cause dependencies to the IOC container to be sprinkled all over the code base.
What you should do is have one central spot in your codebase where all dependencies are resolved and then use dependency injection (DI) to propagate the resolved concrete classes down the chain, i.e via constructor injection. So your class really should look something like this:
public class Foo
{
private readonly IRequestHandler _handler;
public Foo(IRequestHandler handler)
{
_handler = handler;
}
public string DoSomeWork(Request request)
{
return _handler.Handle(request);
}
}

Categories

Resources