Reputation: 103
What's the correct way to propagate the autofac container to and access it from different classes?
The way I understand the documentation, I add the scope to each class as constructor argument and if the calling class was also resolved by autofac, the scope will be injected (not sure if injected is the right term in this context).
Example: Program.cs
using Autofac;
namespace HelloWorld
{
public class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
var builder = new ContainerBuilder();
builder.RegisterType<Class1>();
builder.RegisterType<Class2>();
Container = builder.Build();
var obj1 = Container.Resolve<Class1>();
obj1.Write();
}
}
}
Class1.cs
using Autofac;
namespace HelloWorld
{
internal class Class1
{
public Class1(ILifetimeScope scope)
{
_scope = scope.BeginLifetimeScope();
}
public void Write()
{
var class2 = _scope.Resolve<Class2>();
class2.Write();
}
private readonly ILifetimeScope _scope;
}
}
Class2.cs
namespace HelloWorld
{
internal class Class2
{
public void Write()
{
Console.WriteLine("Hello, I'm class 2.");
}
}
}
Output:
Hello, World!
Hello, I'm class 2.
This example works, however, I feel like the handling of the scope and the manual resolving is quite the overhead. So is this the intended way to use autofac?
Upvotes: 1
Views: 813
Reputation: 23924
There are sort of two questions here. The first is how to propagate scope through classes, which is sort of the literal question; but the second is more implicit, about what you're actually trying to do.
The first question - How do you propagate scope through classes?: You have the right idea for this. If you want to access the lifetime scope from which an object was resolved, you add an ILifetimeScope
property and you can use that to do service location if you need to.
The second question - Is this the intended way to use Autofac?: This is actually larger than Autofac. What you need to do is look at what "dependency injection" and "inversion of control" are. These aren't Autofac-specific patterns.
In general, you shouldn't do service location. Put another way, you should almost never need to inject a lifetime scope and try to resolve something manually. There are exceptions to the rule in interesting edge cases, but that's why I say in general this is the case.
In general, you should just add the constructor parameters you need. That's the whole point of the inversion of control container (in this case, Autofac) - it looks at your constructors and does all the Resolve
and new
calls for you.
There is a great getting started guide in the Autofac docs that shows the basic walkthrough of how you structure your app. I would strongly encourage you to go through those docs and also take some time to research dependency injection. As you search, consider not putting "Autofac" specifically in the list of search terms, since the pattern is much bigger than Autofac, or even .NET - it's a general programming pattern.
To get very specific to your example, you'd change your Class1
so it doesn't do service location. Autofac handles the wire-up.
namespace HelloWorld
{
internal class Class1
{
public Class1(Class2 class2)
{
// Autofac sees this and automatically resolves
// it from the lifetime scope.
_class2 = class2;
}
public void Write()
{
this._class2.Write();
}
private readonly Class2 _class2;
}
}
Upvotes: 3