I have a project A with an IWorker dependency which has many dependencies (context, repositories, etc.). How can I implement IWorker in project B without registering all dependencies? Or what is the correct way to call IWorker in project B?
Example:
Dependency:
public interface IDependency
{
public void SomeMethod();
}
public class SimpleDependemcy : IDependency
{
public void SomeMethod()
{
//Logic
throw new NotImplementedException();
}
}
Worker:
public interface IWorker
{
public void DoWork();
}
public class Worker : IWorker
{
private readonly IDependency _dependency;
public Worker(IDependency dependency)
{
_dependency = dependency;
}
public void DoWork()
{
//Do something
throw new NotImplementedException();
}
}
Registration in project A:
services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();
I want to use worker in project B like:
public class SomeService
{
private readonly IWorker _worker;
public SomeService(IWorker worker)
{
_worker = worker;
}
}
without any registration or simple services.AddScoped<IWorker, Worker>(); in project B. Is it possible? If not, what is correct way to use IWorker implimentation in project B?
Dependency injection work on classes, it does not really care about what project things is in.
The simplest organization is to just make all your registrations in the application project, whatever project that happens to be. But this may cause lots of duplicate code if you have lots of classes and multiple applications using some project.
So you could just delegate registrations to a method in each project:
// In Project A
public static void DoRegistrations(ServiceCollection services){
services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();
}
...
// In ProjectB
public static ServiceProvider CreateServiceProvider(){
var serviceCollection = new ServiceCollection();
ProjectA.Namespace.DoRegistrations(serviceCollection);
serviceCollection.AddTransient<SomeService>();
var container = serviceCollection.BuildServiceProvider();
return container;
}
An more advanced solution is to put the registration method in a class implementing some interface, for example:
public interface IModule{
public void DoRegistrations(ServiceCollection services);
}
This makes it possible to use reflection to find all implementations in all loaded projects, and do all the registrations. A downside with this pattern is that it can be a big WTF-moment for anyone not familiar with the pattern, so use with care.
Whatever solution you end up with, consider writing some automated tests to check that all registrations have been done. It is my experience that missing registrations is a common source of runtime failures, so detecting problems early is useful.
It seems like a common dependency setup. In order to demonstrate I will change IWorker to IMyRepository, and SomeService to MyAppService. So, in this setup, you would (generally speaking) create an abstraction project which defines how a certain dependency should be used and what a certain implementation should adhere to.
I would start by creating the MyProject.Repository.Abstraction project that will contain the repository interface(s).
Then I would implement this interface in a platform specific manner (say MSSQL with MSSQL dependencies) in MyProject.Repositry.Mssql project as MyRepostory:IMyRepository
Similarly, I could create MyProject.Services.Abstractions but it is not relevant. I could now use MyProject.Service project with a reference to MyProject.Repository.Abstractions (not the platform specific implementation project) to implement MyAppService which utilizese the IMyRepository interface.
Finally, the highest level client project, MyProject.Client would reference both the implementation and the abstraction projects to be able to do the dependency injection. This way you can use the abstractions in other projects as reference.
On another note on using this approach, projects with highest abstraction would have higher afferent coupling getting your projects closer to I curve (see also What is Abstractness vs. Instability Graph?).
Related
I have a solution that has the following projects
Acme.Core
Acme.Domain
Acme.Repositories
Acme.Services
Acme.Web
In the past I've used Unity for DI in full framework projects. I was able to register concrete objects to interface mappings in executable projects (web apps, console app, test apps).
I'm trying to implement the same approach with .NET Core. I wanted to first try using the Microsoft.Extensions.DependencyInjection library. Within the ASP.NET Core application it works great. Unfortunately I've run into an issue when I try to share/reference that instance with the registions to other projects, such as a .NET Standard library.
My idea was to inject the ServiceProvider into the constructor of the service:
public class AddressService : BaseService, IAddressService
{
private readonly IServiceProvider _serviceProvider;
public AddressService(IServiceProvider serviceProvider, string userOrProcessName)
{
_serviceProvider = serviceProvider;
}
public IReadOnlyList<IState> GetAllStates()
{
_serviceProvider.GetService<IAddressRepository>();
// other logic removed
}
}
I tried the following inside the Startup.ConfigureServices():
services.AddTransient<IAddressService>(s => new AddressService(HttpContext.RequestServices, Environment.UserName));
The issue I ran into is that I cannot reference HttpContext.RequestServices outside of a Controller. I haven't been able to figure another way of passing the ServiceProvider instance.
My questions:
How do pass a reference for the current ServiceProvider?
Is there a better design to accomplish my goal sharing the configuration of Microsoft.Extensions.DependencyInjection in multiple libraries?
Prevent injecting IServiceProvider into your application components; that leads to the Service Locator anti-pattern.
Instead, you should build up application components solely using Constructor Injection. This means that your AddressService should require IAddressRepository as constructor argument, not IServiceProvider. For instance:
public class AddressService : IAddressService
{
private readonly IAddressRepository repo;
public AddressService(IAddressRepository repo, IUserContext userContext)
{
this.repo = repo;
}
public IReadOnlyList<IState> GetAllStates()
{
// other logic removed
}
}
Also try to prevent injecting primites into your constructors. It's not a bad practice per se, but it does complicate object graph construction. Instead, either wrap the value into a class, in case its a configuration value, or hide it behind an abstraction (as shown above) in case it's a runtime value.
Both practices simplify both your application code and the Composition Root.
For instance, this will be the result of the previous AddressService redesign:
services.AddTransient<IAddressRepository, SqlAddressRepository>();
services.AddTransient<IAddressService, AddressService>();
services.AddScoped<IUserContext, UserContext>();
services.AddHttpContextAccessor();
Here, UserContext could be defined as follows:
public class UserContext : IUserContext
{
private readonly IHttpContextAccessor accessor;
public UserContext(IHttpContextAccessor accessor) => this.accessor = accessor;
public string UserName => this.accessor.HttpContext.User.Identity.Name;
}
In order to share configuration across multiple projects, you can put the configuration into a shared assembly, and register (not resolve) them in there. Many dependency injection libraries offer that functionality. e.g.
in Autofac you create a module (https://autofaccn.readthedocs.io/en/latest/configuration/modules.html) that takes a container builder to configure:
protected override void Load(ContainerBuilder builder) { ... }
SimpleInjector provides packages: https://simpleinjector.readthedocs.io/en/latest/howto.html#package-registrations
Unity can support something similar: Can I register my types in modules in Unity like I can in Autofac?
Ninject has a similar module feature: What is the intention of Ninject modules?
A similar feature has be created for Microsoft.Extensions.DependencyInjection: https://github.com/aruss/DotNetCore_ModularApplication
At a high level, you create a method that receives the DI container and adds your registrations to that container. If your DI framework doesn't provide hooks you need to manually call the method yourself, but the general concept doesn't change.
Splitting registrations into modules allows you to easily group similar sets of functionality while maintaining the flexibility of incorporating different sets of functionality into different projects. You could of course create a single shared assembly that registered the union of all dependencies for all projects, but that would carry around unnecessary baggage and result in a less reusable implementation.
The key point as Steven points out is that you configure the container and let it inject the dependencies rather than looking from the inside out for the dependencies.
The objective is using IoC and being able to [mock dependencies] for unit testing.
The project: .NET Core Web API with multiple class libraries
I'm using Microsoft.Extensions.DependencyInjection for my IoC and I'd like to keep using it if it supports what I'm trying to accomplish.
The problem: At least one class in my assemblies (class libraries) has a dependency that needs to mocked (e.g. using Moq). I completely understand that I can use constructor injection to inject the interface but that doesn't fit the scenario.
What I'm simply trying to accomplish in my assembly is to resolve the dependency using the container that I initiated in my Startup class of the Web API.
How would I do that? And if that isn't possible, what may be another way to accomplish the same thing, i.e. mocking my printer without using dependency injection?
Below is some sample code which hopefully clarifies this a bit.
Web API's Startup.cs (has a reference to assembly which defines printer)
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPrinter, Printer>();
}
In a different assembly, I'd like to resolve an instance of Printer using the same container.
public interface IPrinter
{
void Print(string text);
}
public class Printer : IPrinter
{
public void Print(string text)
{
Console.WriteLine("Printing: " + text);
}
}
public class Task
{
public void PrintSomething(string text)
{
//do not 'new up' but resolve it from the container of Startup.cs
var printer = new Printer();
printer.Print(text);
}
}
This is a design issue masked behind an XY problem.
You have already shot down the The Explicit Dependencies Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
public class PrintTask {
private readonly IPrinter printer;
public PrintTask(IPrinter printer) {
this.printer = printer;
}
public void PrintSomething(string text) {
printer.Print(text);
}
}
Which would allow the dependent class, having already being registered with the container
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<IPrinter, Printer>();
services.AddScoped<PrintTask>();
}
from being a flexible decoupled class whose dependencies could be easily mocked and injected.
Dependency Injection is the best bet here but there is also the Service Locator anti-pattern, which, while workable, is not usually advised.
How can I inject different implementation of object for a specific class?
For example, in Unity, I can define two implementations of IRepository
container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository");
container.RegisterType<IRepository, BaseRepository>();
and call the needed implementation
public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository)
As #Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:
Create a repository resolver:
public interface IRepositoryResolver
{
IRepository GetRepositoryByName(string name);
}
public class RepositoryResolver : IRepositoryResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IRepository GetRepositoryByName(string name)
{
if(name == "TestSuiteRepository")
return _serviceProvider.GetService<TestSuiteRepositor>();
//... other condition
else
return _serviceProvider.GetService<BaseRepositor>();
}
}
Register needed services in ConfigureServices.cs
services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>();
Finally use it in any class:
public class BaselineManager
{
private readonly IRepository _repository;
public BaselineManager(IRepositoryResolver repositoryResolver)
{
_repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
}
}
In addition to #adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.
UPDATE Now it's available as nuget package.
In order to register your services you'll need to add following code to your Startup class:
services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddByName<IService>()
.Add<ServiceA>("key1")
.Add<ServiceB>("key2")
.Add<ServiceC>("key3")
.Build();
Then you can use it via IServiceByNameFactory interface:
public AccountController(IServiceByNameFactory<IService> factory) {
_service = factory.GetByName("key2");
}
Or you can use factory registration to keep the client code clean (which I prefer)
_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));
Full code of the extension is in github.
You can't with the built-in ASP.NET Core IoC container.
This is by design. The built-in container is intentionally kept simple and easily extensible, so you can plug third-party containers in if you need more features.
You have to use a third-party container to do this, like Autofac (see docs).
public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)
After having read the official documentation for dependency injection, I don't think you can do it in this way.
But the question I have is: do you need these two implementations at the same time? Because if you don't, you can create multiple environments through environment variables and have specific functionality in the Startup class based on the current environment, or even create multiple Startup{EnvironmentName} classes.
When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.
I also wrote an article about injecting dependencies from a JSON file so you don't have to recompile the entire application every time you want to switch between implementations. Basically, you keep a JSON array with services like this:
"services": [
{
"serviceType": "ITest",
"implementationType": "Test",
"lifetime": "Transient"
}
]
Then you can modify the desired implementation in this file and not have to recompile or change environment variables.
Hope this helps!
First up, this is probably still a bad idea. What you're trying to achieve is a separation between how the dependencies are used and how they are defined. But you want to work with the dependency injection framework, instead of against it. Avoiding the poor discover-ability of the service locator anti-pattern. Why not use generics in a similar way to ILogger<T> / IOptions<T>?
public BaselineManager(RepositoryMapping<BaselineManager> repository){
_repository = repository.Repository;
}
public class RepositoryMapping<T>{
private IServiceProvider _provider;
private Type _implementationType;
public RepositoryMapping(IServiceProvider provider, Type implementationType){
_provider = provider;
_implementationType = implementationType;
}
public IRepository Repository => (IRepository)_provider.GetService(_implementationType);
}
public static IServiceCollection MapRepository<T,R>(this IServiceCollection services) where R : IRepository =>
services.AddTransient(p => new RepositoryMapping<T>(p, typeof(R)));
services.AddScoped<BaselineManager>();
services.MapRepository<BaselineManager, BaseRepository>();
Since .net core 3, a validation error should be raised if you have failed to define a mapping.
I can't seem to register my Castle Windsor objects by convention and I'm really at a loss. The situation is I have two projects, Website (a really basic web forms project) and BusinessObjects (a class library). I'm attempting to use IoC to be able to keep all of my business object implementations internal, and only deal with the interfaces in the Website project.
The best way that I've found to accomplish this is to use installers. So, in my Global.asax.cs I have this:
private IWindsorContainer _container;
public override void Init()
{
base.Init();
InitializeIoC();
Global.WindsorContainer = _container;
}
private void InitializeIoC()
{
_container = new WindsorContainer();
_container.Install(new BusinessObjectsInstaller());
}
public static IWindsorContainer WindsorContainer { get; private set; }
Which seems to work just fine, and to pull an object out of the container, I'm just using a very simple:
var thingey = Global.WindsorContainer.Resolve<IThingey>();
And then in my BusinessObjects project, I have this:
public class BusinessObjectsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IThingey>().ImplementedBy<Thingey>());
}
}
Now, at this point, everything is working as I expect it to. It's not elegant or anything, but I'm still trying to get a handle on this. So the big thing I'm trying to accomplish at this point is to wire these objects up in a more useful way, which lead me to replacing the above component registration with this:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IThingey>()
.LifestyleTransient()
);
Which I absolutely cannot get to work. All I get is
No component for supporting the service
BusinessObjects.Contracts.IThingey was found
Ultimately the class registration will be changed to another interface that the others inherit from, but one step at a time.
Any help figuring what's going on / what I'm doing wrong would be greatly appreciated.
You are not specifying any service that are registered by your classes, so by default the classes are registered as services to themselves. From the documentation:
By default the service of the component is the type itself
You must specify what services the component is registered against; you do that using the WithService property or shortcut functions (WithServiceBase(), WithServiceDefaultInterfaces(), etc). The linked resource contains the different selections methods you can use:
Base
DefaultInterfaces
FromInterface
AllInterfaces
Self
Select
Krzysztof Kozmic is recommending that you register your components using the Base service, which you would do like this:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IThingey>()
.WithServiceBase()
.LifestyleTransient()
);
we want to use Unity for IOC.
All i've seen is the implementation that there is one global static service (let's call it the the IOCService) which holds a reference to the Unity container, which registers all interface/class combinations and every class asks that object: give me an implementation for Ithis or IThat.
Frequently i see a response that this pattern is not good because it leads to a dependency from ALL classes to the IOCService (not to the Unity container because it is only known inside the IOCService).
But what i don't see often, is: what is the alternative way?
Michel
EDIT: found out that the global static service is called the service locator, added that to the title.
The alternative is to have a single instance of your container at the highest application level only, then use that container to resolve every object instance you need to create in that layer.
For example, the main method of most executables just looks like this (minus exception handling):
private static void main(string[] args) {
Container container = new Container();
// Configure the container - by hand or via file
IProgramLogic logic = container.Resolve<IProgramLogic>();
logic.Run();
}
Your program (represented here by the IProgramLogic instance) doesn't have to know anything about your container, because container.Resolve will create all its dependencies - and its dependencies' dependencies, on down to leaf classes with no dependencies of their own.
ASP.NET is a harder case, because web forms doesn't support constructor injection. I typically use Model-View-Presenter in my web forms applications, so my Page classes really only have one dependency each - on their presenter. I don't unit test them (everything interesting and testable is in my presenters, which I do test), and I don't ever substitute presenters. So I don't fight the framework - I just expose a container property on my HttpApplication class (in global.asax.cs) and use it directly from my Page files:
protected void Page_Load(object sender, EventArgs args) {
ICustomerPresenter presenter = Global.Container.Resolve<ICustomerPresenter>();
presenter.Load();
}
That's service locator of course - though the Page classes are the only thing coupled to the locator: your presenter and all of its dependencies are still fully decoupled from your IoC container implementation.
If you have a lot of dependencies in your Page files (that is, if you do not use Model-View-Presenter), or if it's important to you to decouple your Page classes from your Global application class, you should try to find a framework that integrates into the web forms request pipeline and use property injection (as suggested by Nicholas in the comments below) - or write your own IHttpModule and perform the property injection yourself.
+1 for knowing that Service Locator is a Bad Thing.
Problem is - Unity is not very sophisticated so I don't know how easy/hard is it to do IoC the right way with it.
I wrote few blogposts recently that you might find useful.
How I use IoC Containers
Pulling from the container
Instead of using the container explicitly, use it implicitly by leveraging constructor / property injection instead. Create a core class (or set of core classes) that depend on all the major pieces of your application.
Most containers will let you put ISomething[] in your constructor and it will inject all instances of ISomething into your class.
This way, when you bootstrap your application:
Instantiate your container
Register all your goodies
Resolve the core classes (this will pull in all the other dependencies you need)
Run the "main" part of the application
Now, depending on the type of application you are writing, there are different strategies for avoiding marking the IoC container as "static".
For ASP.NET web applications, you'll probably end up storing the container in the Application State. For ASP.NET MVC applications, you need to change out the Controller Factory.
For desktop applications, things get more complicated. Caliburn uses an interesting solution to this problem using the IResult construct (this is for WPF applications but could be adapted for Windows Forms as well.
In theory, to not have to worry about having a static IoC instance, you need to follow the Fight Club Rule - i.e. not to talk about the fight club - i.e. not to mention the IoC container.
This means that your components should largely be unaware about the IoC container. It should only be used at the topmost level when registering components. If a class needs to resolve something, it should really be injected as a dependency.
The trivial case is easy enough. If PaymentService depends on IAccount, the latter should be injected by IoC:
interface IAccount {
Deposit(int amount);
}
interface CreditCardAccount : IAccount {
void Deposit(int amount) {/*implementation*/}
int CheckBalance() {/*implementation*/}
}
class PaymentService {
IAccount account;
public PaymentService (IAccount account) {
this.account = account;
}
public void ProcessPayment() {
account.Deposit(5);
}
}
//Registration looks something like this
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();
The not so trivial case is where you want to inject multiple registrations. This especialy applies when you are doing any sort of Converntion Over Configuration and creating an object from a name.
For our payment example, say you want to enumerate through all accounts and check their balances:
class PaymentService {
IEnumerable<IAccount> accounts;
public PaymentService (IEnumerable<IAccount> accounts) {
this.accounts = accounts;
}
public void ProcessPayment() {
foreach(var account in accounts) {
account.Chackbalance();
}
}
}
Unity has the ability to register multiple interface to class mappings (they have to have different names thought). It does not, however, automatically inject those into classes that take collections of those registered interfaces. So, the above example will throw a resolution failed exception at runtime.
If you don't care that those objects live forever, you can register PaymentService in a more static fashion:
container.RegisterType<PaymentService>(new InjectionConstructor(container.ResolveAll<IAccount>()));
The above code will register PaymentService and will use a collection of IAccount instances that is resolved at registration time.
Alternatively, you can pass an instance of the container itself as a dependency and let PaymentService perform resolution of accounts. This is not quite following the Fight Club Rule, but is slightly less smelly than static Service Locator.
class PaymentService {
IEnumerable<IAccount> accounts;
public PaymentService (IUnityContainer container) {
this.accounts = container.ResolveAll<IAccount>();
}
public void ProcessPayment() {
foreach(var account in accounts) {
account.Chackbalance();
}
}
}
//Registration is pretty clean in this case
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();
container.RegisterInstance<IUnityContainer>(container);
If your concern is having a dependency on Unity throughout your application, you can combine the service locator with a facade to hide the IOC implementation. In this way, you do not create a dependency on Unity in your application, only on having something that can resolve types for you.
For example:
public interface IContainer
{
void Register<TAbstraction,TImplementation>();
void RegisterThis<T>(T instance);
T Get<T>();
}
public static class Container
{
static readonly IContainer container;
public static InitializeWith(IContainer containerImplementation)
{
container = containerImplementation;
}
public static void Register<TAbstraction, TImplementation>()
{
container.Register<TAbstraction, TImplementation>();
}
public static void RegisterThis<T>(T instance)
{
container.RegisterThis<T>(instance);
}
public static T Get<T>()
{
return container.Get<T>();
}
}
Now all you need is an IContainer implementation for your IOC container of choice.
public class UnityContainerImplementation : IContainer
{
IUnityContainer container;
public UnityContainerImplementation(IUnityContainer container)
{
this.container = container;
}
public void Register<TAbstraction, TImplementation>()
{
container.Register<TAbstraction, TImplementation>();
}
public void RegisterThis<T>(T instance)
{
container.RegisterInstance<T>(instance);
}
public T Get<T>()
{
return container.Resolve<T>();
}
}
Now you have a service locator that is a facade for IOC services, and can configure your service locator to use Unity or any other IOC container. The rest of the application has no dependency on the IOC implementation.
To configure your service locator:
IUnityContainer unityContainer = new UnityContainer();
UnityContainerImplementation containerImpl = new UnityContainerImplementation(unityContainer);
Container.InitializeWith(containerImpl);
For testing, you can create a stub of IContainer that returns whatever you want, and initialize Container with that.