Yet another IOC container for .NET, designed from the ground up to support the ASP.NET Core DI abstractions.
The second responsibility of an IOC container, in the Register-Resolve-Release pattern, is to resolve a service. There are two ways of doing so:
The first option is called service location while the second option is called dependency injection.
The best practice for using IOC containers is to request only your topmost
service from the container – or even better still, to leave your application
framework to do so for you – and use dependency injection to handle the rest.
For example, in a console application, you would only want to perform a service
location in your program’s Main method, while in ASP.NET Core, all that is
handled for you behind the scenes, and any services that you register are
injected directly into your controllers.
To get your root service, call the GetService method:
static int Main(string[] args)
{
var myModule = CreateModule();
using (var container = Configuration.CreateContainer(myModule))
{
myProgram = container.GetService<Program>();
return myProgram.Run(args);
}
}
For anything else, you should just leave FactoryFactory to inject dependencies
into your service’s constructor. For example, your Program class might look
like this:
public class Program
{
private IClock _clock;
public Program(IClock clock)
{
_clock = clock;
}
public int Run(string[] args)
{
Console.WriteLine($"Hello world, the time is {_clock.UtcNow}");
}
}
What you shouldn’t do is pepper your codebase with calls to FactoryFactory all over the place. For example, don’t do this:
public class Program
{
private IClock _clock;
public Program()
{
_clock = Global.Container.GetService<IClock>();
}
public int Run(string[] args)
{
Console.WriteLine($"Hello world, the time is {_clock.UtcNow}");
}
}
It is possible to define multiple implementations of a service:
module.Define<IPasswordHashProvider>().As<Argon2HashProvider>();
module.Define<IPasswordHashProvider>().As<SCryptHashProvider>();
module.Define<IPasswordHashProvider>().As<BCryptHashProvider>();
module.Define<IPasswordHashProvider>().As<PBKDF2HashProvider>();
You can ask FactoryFactory for all of them, by requesting IEnumerable<T>:
public class UsersService
{
private IUsersRepsoitory _usersRepository;
private List<IPasswordHashProvider> _hashProviders;
public UsersService(IUsersRepository usersRepository,
IEnumerable<IPasswordHashProvider> hashProviders)
{
_usersRepository = usersRepository;
_hashProviders = hashProviders.ToList();
}
}
Services in this case will be returned in the order in which they were
registered. You can also request a collection of services by asking for
ICollection<T>, IReadOnlyCollection<T>, IList<T> or List<T>.
If no services have been registered for a particular type, the collection will be empty, even if the service requested has a public constructor and could be resolved automatically as a single instance.
It frequently happens that you have a service which relies on serveral dependencies, some of which might not be used. For example, a controller action won’t need to use any of its dependent services if a user is not logged in.
In this case, you can request your services as a Lazy<TDependency>. For
example:
public class AdminService
{
private ISecurityContext _context;
private Lazy<IUserManagementRepository> _userManagementRepository;
public AdminService(ISecurityContext context,
Lazy<IUserManagementRepository> userManagementRepository)
{
_context = context;
_userManagementRepository = userManagementRepository;
}
public IEnumerable<User> GetAllUsers()
{
if (!_context.IsAdmin) {
throw new AccessDeniedException("Admins only!");
/*
* _userManagementRepository won't get created if the
* user is not an admin.
*/
}
return _userManagementRepository.GetAllUsers();
}
}
Project maintained by jammycakes • Hosted on GitHub Pages — Theme by mattgraham (with modifications)