Register container itself with Autofac

I was wondering if there is any side effect to registering the container inside myself

IContainer container; ContainerBuilder builder = new ContainerBuilder(); container = builder.Build(); builder.RegisterInstance(container).As<IContainer>(); 

and use it like that

 builder.RegisterType<IManagmentServiceImp>().As<ManagmentServiceImp>() .WithParameter(new ResolvedParameter( (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container", (pi, ctx) => container )); 

or it will even work.

+5
source share
4 answers

Your code is unsafe because you register an instance before it is initialized.

If you need access to the container inside the component (this is not a good idea), you can have a dependency on ILifetimeScope , which have Resolve methods.

 public class ManagmentServiceImp { public ManagmentServiceImp(ILifetimeScope scope) { } } 

ILifetimeScope automatically registered in Autofac, you do not need to add registration to it.

For more information, see Managing Scope and Lifetime from the Autofac Documentation.

By the way, this is not a good practice for depending on your IoC container. It looks like you are using an anti-pattern Service Locator . If you need a container for lazy load dependency, you can use a composition with Func<T> or Lazy<T>

 public class ManagmentServiceImp { public ManagmentServiceImp(Lazy<MyService> myService) { this._myService = myService; } private readonly Lazy<MyService> _myService; } 

In this case, MyService will be created upon first access to it.

For more information, see Implicit Relationship from the Autofac documentation.

+11
source

You can use this extension method:

 public static void RegisterSelf(this ContainerBuilder builder) { IContainer container = null; builder.Register(c => container).AsSelf(); builder.RegisterBuildCallback(c => container = c); } 

use it as follows: builder.RegisterSelf();

+2
source

Since you need to provide a container instance for builder.RegisterInstance() , you need to initialize it before passing it as an argument that you are not currently running. However, if you structure the container builder to create AFTER registration (and container initialization), you can successfully resolve the container instance in your class.

Please note that this is definitely the smell of design in Dependency Injection, and you absolutely shouldn't. Your container / core should only exist at the top level of your object graph. If you start entering your container, you are almost certainly on the way to the Locator anti-pattern.

 void Main() { IContainer container = new ContainerBuilder().Build(); ContainerBuilder builder = new ContainerBuilder(); builder.RegisterInstance(container).As<IContainer>(); builder.RegisterType<ManagementServiceImp>().As<IManagmentServiceImp>() .WithParameter(new ResolvedParameter( (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container", (pi, ctx) => container )); container = builder.Build(); var instance = container.Resolve<IManagmentServiceImp>(); } public class ManagementServiceImp : IManagmentServiceImp { private IContainer _container; public ManagementServiceImp(IContainer Container) { _container = Container; _container.Dump(); } } public interface IManagmentServiceImp { } 
+1
source

While I do not answer your question. Trying to get a container handle in a service class or something other than the IModule equivalent is the smell of code.

Your service code should not know anything about IOC IMO.

0
source

Source: https://habr.com/ru/post/1247795/


All Articles