Autofac Singleinstance With Two Interfaces Being Constructed Again in Factoruy
Or, "Avoiding Retentiveness Leaks in Managed Composition"
Understanding lifetime tin be pretty tough when you lot're new to IoC. Even long-fourth dimension users express vague fears and misgivings when information technology comes to this subject area, and disconcerting issues – components not being disposed, steadily climbing memory usage or an OutOfMemoryException
– accept bitten many of us at one fourth dimension or another.
Avoiding lifetime issues when using an IoC container is generally straightforward, but doing then successfully is more than a question of application pattern rather than just container API usage. In that location's lots of good advice out there, only very fiddling of information technology tells the complete story from beginning to finish. I've attempted to do that with this rather long article, and hope that with a scrap of feedback from you information technology tin can exist shaped into a useful reference.
This article is most Autofac, merely the broad issues are universal – even if you're not an Autofac user, chances are there'south something to larn about your container of pick.
What Leaks?
Allow's brainstorm with the issue that in all likelihood brought y'all here. Tracking containers like Autofac agree references to the dispensable components they create.
Past disposable we mean any component that implements the BCL's IDisposable
interface (or is configured with an OnRelease()
action):
interface IMyResource { … } class MyResource : IMyResource , IDisposable { … }
When an instance of MyResource
is created in an Autofac container, the container will hold a reference to it even when it is no longer existence used past the rest of the program. This means that the garbage collector volition be unable to reclaim the retentivity held by that component, so the following program volition eventually exhaust all bachelor memory and crash:
var builder = new ContainerBuilder (); builder . RegisterType < MyResource >(). Equally < IMyResource >(); using ( var container = builder . Build ()) { while ( true ) var r = container . Resolve < IMyResource >(); // Out of memory! }
This is a far weep from typical CLR behaviour, which is one more than reason why it is expert to get abroad from thinking near an IoC container as a replacement for new
. If we'd only created MyResource
directly in the loop, there wouldn't exist any problem at all:
while ( true ) var r = new MyResource (); // Fine, feed the GC
Transitive Dependencies
Looking at the lawmaking above you might be tempted to call back that the problem merely surfaces when dispensable components are resolved directly from the container. That's non really the case - every disposable component created by the container is tracked, even those created indirectly to satisfy dependencies.
interface IMyService { } class MyComponent : IMyService { // Dependency on a service provided past a disposable component public MyComponent ( IMyResource resource ) { … } }
If a second component is resolved that depends on a service provided by a dispensable component, the retention leak however occurs:
while ( true ) // Still holds instances of MyResource var s = container . Resolve < IMyService >();
Results Returned from Delegate Factories
Rather than calling Resolve()
straight on an IContainer
we might instead accept a dependency on an Autofac consul factory type like Func<T>
:
interface IMyService2 { void Go (); } class MyComponent2 : IMyService2 { Func _resourceFactory ; public MyComponent ( Func < IMyResource > resourceFactory ) { _resourceFactory = resourceFactory ; } public void Go () { while ( truthful ) var r = _resourceFactory (); // However out of memory. } }
Now in the main loop nosotros merely resolve one component instance and call the Go()
method.
using ( var container = builder . Build ()) { var s = container . Resolve < IMyService2 >(); s . Go (); }
Even though we've only called the container one time directly, the leak is withal there.
Why does Autofac behave this mode?
Information technology might seem that there are several traps here, though at that place's really only ane – and information technology is worth reiterating:
Autofac will rails every disposable component instance that it creates, no thing how that instance is requested.
This isn't, of course, the finish of the road. Autofac is very carefully designed to make resource management easier than programming without a container. Observe I slipped in the discussion resources there? The 'retention leaks' we're talking about are a result of preventing another kind of 'leak' – the resource that are managed through IDisposable
.
What are Resources?
Traditionally, a resource might be defined as annihilation with finite capacity that must exist shared between its users.
In the context of components in an IoC container, a resource is anything with acquisition and release phases in its lifecycle. Many depression-level examples be, such as components that rely on items from the list beneath, but information technology is besides very common to find loftier-level application constructs with similar semantics.
- Locks (east.chiliad.
Monitor.Enter()
andMonitor.Go out()
) - Transactions (
Begin()
andCommit()
/Abort()
) - Consequence subscriptions (
+=
and-=
) - Timers (
Kickoff()
andDispose()
) - Machine resources like sockets and files (usually
Open()
/Create()
andShut()
) - Waiting worker threads (
Create()
andIndicate()
)
In .Net there's a standard way to represent resource semantics on a component by implementing IDisposable
. When such a component is no longer required, the Dispose()
method must exist called to complete the 'release' phase.
Non Calling Dispose() is most often a Bug
You lot can read some interesting discussions via Kim Hamilton'due south and Joe Duffy's articles on the topic of when Dispose()
must be called.
There's a fairly strong consensus that more often than not, failing to call Dispose()
volition lead to a problems, regardless of whether or non the resources in question is protected past a finalizer (or SafeHandle
).
What is less clear is how applications and APIs should be structured and so that Dispose()
can exist called reliably and at the correct fourth dimension.
IDisposable and Ownership
Before IoC (assuming you use it now) in that location were probably two approaches y'all could utilize to calling Dispose()
:
- The C#
using
statement - Advertising-hoc
IDisposable
and using
are a match fabricated in heaven, but they only employ when a resources's lifetime is within a unmarried method call.
For everything else, you demand to notice a strategy to ensure resources are disposed when they're no longer required. The near widely-attempted one is based around the thought that any object acquires the resource should too release it. I pejoratively call it "ad-hoc" because it doesn't work consistently. Somewhen you lot'll come confronting one (and likely more than) of the following issues:
Sharing: When multiple independent components share a resource, it is very hard to effigy out when none of them requires it any more. Either a 3rd political party will accept to know about all of the potential users of the resource, or the users will accept to collaborate. Either style, things go hard fast.
Cascading Changes: Let's say we have three components – A
uses B
which uses C
. If no resources are involved, then no thought needs to be given to how resource ownership or release works. Merely, if the awarding changes so that C
must now ain a dispensable resource, then both A
and B
will probably accept to change to point appropriately (via disposal) when that resources is no longer needed. The more components involved, the nastier this one is to unravel.
Contract vs. Implementation: In .NET nosotros're encouraged to program to a contract, non an implementation. Well-designed APIs don't usually give details of the implementation type, for instance an Abstract Factory could be employed to create caches of different sizes:
public ICache CreateCache ( int maximumByteSize ); // Abstruse Factory interface ICache // : IDisposable? { void Add together ( object key , object value , TimeSpan ttl ); bool TryLookup ( object fundamental , out object value ); }
The initial implementation may render only MemoryCache
objects, that have no resource direction requirements. All the same, because we may in hereafter create a FileCache
implementation, does that mean that ICache
should be disposable?
The root of the problem here is that for whatever contract, information technology is conceivable that there volition i 24-hour interval be an implementation that is disposable.
This detail trouble is exacerbated by loosely-coupled systems like those built with IoC. Since components only know most each other through contracts (services) and never their implementation types, there actually isn't whatsoever manner for 1 component to determine whether it should try to dispose another.
IoC to the Rescue!
In that location is a viable solution out there. Every bit you tin can guess, a) in typical enterprise and web applications and b) at a certain level of granularity IoC containers provide a good solution to the resource management trouble.
To exercise this, they need to take ownership of the dispensable components that they create.
But this is merely part of the story – they as well need to be told virtually the units of work that the application performs. This is how the container will know to dispose components and release references, avoiding the memory leak problems that will otherwise occur.
Why not accept the container use WeakReference just to be safe? A solution that relies on WeakReference
is afflicted past the aforementioned problems as not calling Dispose()
at all. Allowing components to be garbage collected before the enclosing unit of piece of work is complete tin lead to a whole class of subtle load- and environment-dependent bugs. Many higher-level resources are also unable to be properly released inside a finalizer.
Units of Work
Every bit they run, enterprise and spider web applications tend to perform tasks with a divers beginning and end. These tasks might be things similar responding to a web request, handling an incoming message, or running a batch procedure over some data.
These are tasks in the abstract sense – not to be dislocated with something similar Chore
or whatever of the asynchronous programming constructs. To make this clearer, we'll co-opt the term 'unit of work' to describe this kind of chore.
Determining where units of work begin and finish is the key to using Autofac effectively in an application.
Lifetime Scopes: Implementing Units of Piece of work with Autofac
Autofac caters to units of work through lifetime scopes. A lifetime scope (ILifetimeScope
) is only what it sounds like – a scope at the completion of which, the lifetime of a set of related components volition terminate.
Component instances that are resolved during the processing of a unit of measurement of work get associated with a lifetime telescopic. By tracking instantiation social club and ensuring that dependencies can only be satisfied past components in the same or a longer-lived lifetime telescopic, Autofac can take responsibility for disposal when the lifetime scope ends.
Going dorsum to our original piffling case, the leak we observed tin can be eliminated by creating and disposing a new lifetime scope each time we go through the loop:
// var container = … while ( true ) { using ( var lifetimeScope = container . BeginLifetimeScope ()) { var r = lifetimeScope . Resolve < IMyResource >(); // r, all of its dependencies and any other components // created indirectly will exist released hither } }
This is all it takes to avoid memory and resource leaks with Autofac.
Don't resolve from the root container. Always resolve from and then release a lifetime scope.
Lifetime scopes are extremely flexible and can be practical to a huge range of scenarios. There are a few handy things to know that might non be immediately obvious.
Lifetime Scopes can Exist Simultaneously
Many lifetime scopes can exist simultaneously on the same container. This is how incoming HTTP requests are handled in the Autofac ASP.NET integration, for instance. Each request causes the creation of a new lifetime telescopic for handling it; this gets disposed at the finish of the request.
Note that we call the root of the lifetime telescopic bureaucracy the 'Application' scope, because it will live for the duration of an application run.
Lifetime Scopes can be Nested
The container itself is the root lifetime scope in an Autofac application. When a lifetime telescopic is created from it, this sets upwardly a parent-child human relationship betwixt the nested telescopic and the container.
When dependencies are resolved, Autofac start attempts to satisfy the dependency with a component instance in the scope in which the request was made. In the diagram beneath, this means that the dependency on an NHibernate session is satisfied within the scope of the HTTP asking and the session will therefore be tending when the HTTP request scope ends.
When the dependency resolution process hits a component that cannot be resolved in the current scope – for instance, a component configured as a Singleton using SingleInstance()
, Autofac looks to the parent telescopic to see if the dependency tin can be resolved at that place.
When the resolve operation has moved from a child telescopic to the parent, any further dependencies volition be resolved in the parent scope. If the SingleInstance()
component Log
depends on LogFile
then the log file dependency volition exist associated with the root scope, then that even when the electric current HTTP request scope ends, the file component volition live on with the log that depends on it.
Lifetime scopes can be nested to arbitrary depth:
var ls1 = container . BeginLifetimeScope (); var ls2 = ls1 . BeginLifetimeScope (); // ls1 is a child of the container, ls2 is a child of ls1
Sharing is driven by Lifetime Scopes
At this signal in our discussion of lifetime management (you thought nosotros were going to talk about retentivity leaks but that's just how I roped yous in!) it is worth mentioning the human relationship betwixt lifetime scopes and how Autofac implements 'sharing'.
By default, every time an instance of a component is needed (either requested direct with the Resolve()
method or as a dependency of another component) Autofac will create a new example and, if information technology is disposable, attach it to the current lifetime scope. All IoC containers that I know of support something like this kind of 'transient lifestyle' or 'instance per dependency.'
Likewise universally supported is 'singleton' or 'single instance' sharing, in which the same instance is used to satisfy all requests. In Autofac, SingleInstance()
sharing volition associate an case with the root node in the tree of active lifetime scopes, i.e. the container.
There are two other common sharing modes that are used with Autofac.
Matching Telescopic Sharing
When creating a telescopic, it is possible to give it a name in the form of a 'tag':
// For each session meantime managed past the application var sessionScope = container . BeginLifetimeScope ( "session" ); // For each message received in the session: var messageScope = sessionScope . BeginLifetimeScope ( "message" ); var dispatcher = messageScope . Resolve < IMessageDispatcher >(); dispatcher . Dispatch ( … );
Tags name the levels in the lifetime scope bureaucracy, and they can be used when registering components in order to determine how instances are shared.
builder . RegisterType < CredentialCache >() . InstancePerMatchingLifetimeScope ( "session" );
In this scenario, when processing letters in a session, even though nosotros always Resolve()
dependencies from the messageScope
due south, all components will share a unmarried CredentialCache
at the session level.
Current Scope Sharing
While occasionally units of piece of work are nested multiple layers deep, most of the time a single executable will deal with merely one kind of unit of measurement of piece of work.
In a web application, the 'child' scopes created from the root are for each HTTP request and might exist tagged with "httpRequest"
. In a back-end process, we may too take a 2-level telescopic hierarchy, but the kid scopes may be per-"workItem"
.
Many kinds of components, for example those related to persistence or caching, need to be shared per unit of work, regardless of which awarding model the component is beingness used in. For these kinds of components, Autofac provides the InstancePerLifetimeScope()
sharing model.
If a component is configured to use an InstancePerLifetimeScope()
then at most a single case of that component will be shared between all other components with the same lifetime, regardless of the level or tag associated with the scope they're in. This is great for reusing components and configuration betwixt different applications or services in the same solution.
Lifetime Scopes don't have any Context Dependency
It is completely acceptable to create multiple contained lifetime scopes on the aforementioned thread:
var ls1 = container . BeginLifetimeScope (); var ls2 = container . BeginLifetimeScope (); // ls1 and ls2 are completely independent of each other
It is also perfectly safe to share a single lifetime scope between many threads, and to cease a lifetime scope on a thread other than the one that began it.
Lifetime scopes don't rely on thread-local storage or global country like the HTTP context in order to do their work.
Components tin Create Lifetime Scopes
The container tin can exist used straight for creating lifetime scopes, but well-nigh of the fourth dimension you won't want to employ a global container variable for this.
All a component needs to do to create and use lifetime scopes is to accept a dependency on the ILifetimeScope
interface:
form MessageDispatcher : IMessageDispatcher { ILifetimeScope _lifetimeScope ; public MessageDispatcher ( ILifetimeScope lifetimeScope ) { _lifetimeScope = lifetimeScope ; } public void OnMessage ( object message ) { using ( var messageScope = _lifetimeScope . BeginLifetimeScope ()) { var handler = messageScope . Resolve < IMessageHandler >(); handler . Handle ( bulletin ); } } }
The ILifetimeScope
instance that is injected will exist the one in which the component 'lives.'
Owned Instances
Owned instances (Owned<T>
) are the last tale in Autofac's lifetime story.
An owned instance is a component that comes wrapped in its own lifetime telescopic. This makes it easier to keep runway of how a component should be released, especially if it is used outside of a using
statement.
To get an owned instance providing service T
, you tin resolve 1 straight from the container:
var ownedService = container . Resolve < Owned < IMyService >>();
In lifetime terms, this is equivalent to creating a new lifetime scope from the container, and resolving IMyService
from that. The just difference is that the IMyService
and the lifetime scope that holds information technology come wrapped upward together in a single object.
The service implementation is available through the Value
property:
// Value is IMyService ownedService . Value . DoSomething ();
When the owned case is no longer needed, it and all of its dispensable dependencies can exist released past disposing the Owned<T>
object:
Combining with Func Factories
Autofac automatically provides Func<T>
every bit a service when T
is registered. Every bit we saw in an earlier example, components tin can use this mechanism to create instances of other components on the fly.
class MyComponent2 : IMyService2 { Func < IMyResource > _resourceFactory ; public MyComponent ( Func < IMyResource > resourceFactory ) { _resourceFactory = resourceFactory ; } public void Go () { while ( true ) var r = _resourceFactory (); // Out of retentivity. } }
Components that are returned from Func<T>
delegates are associated with the same lifetime scope every bit the consul itself. If that component is itself contained in a lifetime scope, and information technology creates a finite number of instances through the delegate, then there's no problem – everything will be cleaned upward when the scope completes.
If the component calling the delegate is a long-lived 1, and then the instances returned from the consul volition need to exist cleaned up eagerly. To practice this, Owned<T>
can be used as the return value of a factory delegate:
class MyComponent2 : IMyService2 { Func < Owned < IMyResource >> _resourceFactory ; public MyComponent ( Func < Owned < IMyResource >> resourceFactory ) { _resourceFactory = resourceFactory ; } public void Go () { while ( true ) using ( var r = _resourceFactory ()) // Use r.Value before disposing information technology } }
Func<T>
and Endemic<T>
tin exist combined with other relationship types to ascertain relationships with a clearer intent than only taking a dependency on ILifetimeScope
.
Practice I really take to think about all this stuff?
That concludes our tour of lifetime management with Autofac. Whether you employ an IoC container or not, and whether you use Autofac or some other IoC container, non-footling applications have to deal with the kinds of issues we've discussed.
Once you've wrapped your heed around a few key concepts, you lot'll find that lifetime rarely causes any headaches. On the plus side, a huge range of difficult application design problems effectually resource direction and ownership will disappear.
Just remember:
- Autofac holds references to all the disposable components it creates
- To prevent memory and resource leaks, ever resolve components from lifetime scopes and dispose the scope at the conclusion of a task
- Effectively using lifetime scopes requires that you clearly map out the unit of piece of work construction of your applications
- Endemic instances provide an brainchild over lifetime scopes that can be cleaner to piece of work with
Happy programming!
scarbroughupout1948.blogspot.com
Source: https://nblumhardt.com/2011/01/an-autofac-lifetime-primer/
0 Response to "Autofac Singleinstance With Two Interfaces Being Constructed Again in Factoruy"
Post a Comment