Autofac Lifecycle Management

I am working on an ASP.NET MVC project that supports external plugins, now I am switching from Unity to Autofac, and I need to wrap Lifeof Autofac objects so that the plugins cannot reference it, in Unity I could do something.

public sealed class UnityScopeFactory : IDependencyScopeFactory { private HttpRequestScope _httpRequest; private SingletonScope _singleton; private TransientScope _transient; public IDependencyScope HttpRequest() { return _httpRequest ?? (_httpRequest = new HttpRequestScope()); } public IDependencyScope Singleton() { return _singleton ?? (_singleton = new SingletonScope()); } public IDependencyScope Transient() { return _transient ?? (_transient = new TransientScope()); } private class HttpRequestScope : IDependencyScope { public object CreateScope() { return new HttpPerRequestLifetimeManager(); } } private class SingletonScope : IDependencyScope { public object CreateScope() { return new ContainerControlledLifetimeManager(); } } private class TransientScope : IDependencyScope { public object CreateScope() { return new TransientLifetimeManager(); } } } 

I did a similar thing in Autofac, but I'm not sure if this is the right way to do this, I looked at Autofac's RegistrationBuilder, which (unfortunately) is internal, and I came up with this.

 public class AutofacScopeFactory : IDependencyScopeFactory { private HttpRequestScope _httpRequest; private SingletonScope _singleton; private TransientScope _transient; public IDependencyScope HttpRequest() { return _httpRequest ?? (_httpRequest = new HttpRequestScope()); } public IDependencyScope Singleton() { return _singleton ?? (_singleton = new SingletonScope()); } public IDependencyScope Transient() { return _transient ?? (_transient = new TransientScope()); } private class HttpRequestScope : IDependencyScope { public object CreateScope() { return new CurrentScopeLifetime(); } } private class SingletonScope : IDependencyScope { public object CreateScope() { return new RootScopeLifetime(); } } private class TransientScope : IDependencyScope { public object CreateScope() { return new CurrentScopeLifetime(); } } } 

Also, after I got this to work, how can I use it to pass it to ContainerBuilder?

In Unity, I could do something like this.

 public sealed class UnityDependencyContainer : IDependencyContainer { private readonly IUnityContainer _container; public UnityDependencyContainer() { _container = new UnityContainer() } public void Register<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract { LifetimeManager manager = scope.CreateScope() as LifetimeManager; if (manager != null) { _container.RegisterType<TContract, TImplementation>(manager); } } } 

How to pass an instance of IComponentLifetime to a chain of methods? is this a dead end

 public class AutofacContainer : IDependencyContainer { private static readonly ContainerBuilder Builder; static AutofacContainer() { Builder = new ContainerBuilder(); } public void RegisterType<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract { IComponentLifetime manager = scope.CreateScope() as IComponentLifetime; if (manager != null) { Builder.RegisterType<TImplementation>().As<TContract>(); } } } 
+6
source share
1 answer

Autofac does not separate the scope as you drew it, so you can set the square snap in the round hole .

Autofac areas are more hierarchical. Any life span can give rise to a time frame for children. For example, you can see ...

  • Container / Root Life
    • HttpRequest Area
      • Scalable task-specific scope

You can “mark” a region and register components for a specific region with a name / tags - how the HttpRequest region works. It gets "tagged" with a special identifier.

When you resolve objects, this is when it determines which life resource belongs to it. Resolution comes from the nested area itself. In the hierarchy above, you allow items from a small transient target cloud, whether they are solitary, to request scope or anything else. When a singleton is resolved, it will search for the life scale stack and automatically assign the “ownership” of the object to the life cycle area. When an item for a request is requested, it searches the stack for the lifetime using the special HTTP request identifier and assigns ownership of it. Factory -scoped elements are allowed in the current scope.

Note. This discussion is a gross simplification of the work. There is documentation explaining the lifelong visibility mechanism on the Autofac site.

Point, I see some things in the design above that don't really “jive” with how Autofac works.

DependencyScopeFactory cannot create its own temporary regions or HttpRequest regions. There are specific lifecycle management components that start and end the HttpRequest scope, so you will need to use them; There is no "global" time domain, so you cannot just create it.

The HttpRequest area assuming you are using MVC will be more like ...

 public ILifetimeScope HttpRequestScope { get { return AutofacDependencyResolver.Current.RequestLifetime; } } 

There is no analogue for the time domain, since the use on it should be built-in:

 using(var transientScope = parentScope.BeginLifetimeScope()) { // Do stuff and resolve dependencies using the transient scope. // The IDisposable pattern here is important so transient // dependencies will be properly disposed at the end of the scope. } 

When you register components, you do not register them "in the area of ​​the lifetime." . You register them in the component registry, and the component registration part includes information on the component owner after its permission.

 var builder = new ContainerBuilder(); // This component is factory-scoped and will be "owned" by whatever // lifetime scope resolves it. You can resolve multiple of these // in a single scope: builder.RegisterType<FirstComponent>().As<ISomeInterface>(); // This component is a singleton inside any given lifetime scope, // but if you have a hierarchy of scopes, you'll get one in each // level of the hierarchy. builder.RegisterType<SecondComponent>().InstancePerLifetimeScope(); // This component will be a singleton inside a specifically named // lifetime scope. If you try to resolve it in a scope without that // name, it'll search up the scope stack until it finds the scope // with the right name. If no matching scope is found - exception. builder.RegisterType<ThirdComponent>().InstancePerMatchingLifetimeScope("scopename"); // This is a per-HTTP-request component. It just like the // above InstancePerMatchingLifetimeScope, but it has a special // tag that the web integration knows about. builder.RegisterType<FourthComponent>().InstancePerHttpRequest(); 

If you are trying to create an agnostic container / registration interface, it will not need a "lifetime visibility manager . " Instead, you will need to pass some parameters indicating the expected lifetime of the scope and execute the appropriate registration syntax (above) based on the incoming parameters.

Again, I would recommend that you check this documentation .

In addition, if you use Unity, Autofac has the Configurator package for the corporate library that allows you to configure Autofac in the Unity style (since EntLib loves to do something). It might be something to check.

If you don't need to use Unity syntax at all ... I would recommend just moving on to do something in Autofac's own path. . Trying to make one container look and act like another is a rather painful effort.

Assuming your plugins are in separate assemblies or something else, you can easily take advantage of the strong assembly syntax and Autofac modules and plug in your plugins this way.

+9
source

All Articles