I am writing a console app in .Net core. I want to use dependency injection. My architecture is like this. Program contains a TradeProcessor (which does all the work) which in turn makes some CompoundTrades. I have got DI passing some classes into the TradeProcessor via its constructor and that whole ServiceProvider setup. That works fine.
Now, if i want to DI some classes into the CompoundTrade does the TradeProcessor have to pass them in via the constructor? I was under the impression that if you register the class to be constructed, all the classes you want to pass in, then they all got passed in "under the hood". You call CompoundTrade () but the other constructor gets called. Am i confusing that with DI in Asp.Net? What is the best design pattern for doing this? Stick all the ServiceProviders in a static class?
You call CompoundTrade() but the other constructor gets called.
That's not how dependency injection works. If you call a constructor explicitly, you get exactly that constructor.
You will need to reference you container and tell your container to create an instance of that class for you.
If you have an instance that needs to dynamically create new objects that are registered in the container, you will need to pass in the container and then use that to create those new objects. Don't call a constructor directly.
public TradeProcessor(IServiceProvider provider)
{
// save the provider in a field
}
public void ThisNeedsADynamicallyCreatedContainerObject()
{
if(condition)
{
var instance = this.provider.GetService<ICompoundTrade>();
}
else
{
var instance = this.provider.GetService<ISingleTrade>();
}
}
Disclaimer: actual syntax may vary depending on the dependency injection provider you use.
Related
Preface - we have an old service that we need to upkeep and occasionally modify. Its architecture is not good, and it is a mammoth, but since we hope to deprecate it eventually my company does not want to currently fix its architecture.
Question:
I have a class MS. I need to change one of its methods so that instead of calling HTTP directly, it will do so via another existing class, AEO. AEO inherits from abstract class EC, has several fields it receives by means of DI, and is set up to be received by DI as well.
MS is not created via DI. Rather, the program.cs file that calls the method that adds DI, it creates a new instance of MS, manually passing its necessary parameters in.
How can I access AEO from within MS? If I just create new AEO(...) I will have an issue with passing the DI parameters which I do not have. If I just declare the Interface/Indexer as I would with normal DI, then upon creating new MS(...) I will have an issue of lacking the parameter to pass in to the constructor.
How can I make this work? Is it possible?
TIA
EDIT:
The way that AEO is declared with DI is thus:
builder.RegisterType<AEO>().Keyed<EC>(MCType.AEO)
.SingleInstance().WithAttributeFiltering();
answer edited 15-Dec-2022
Whenever I've had to perform this kind of refactoring in the past I've approached it from a different angle.
In order to mitigate risk the first step is to introduce your old service to the dependency injection process.
This will allow you to introduce replacement services, again using DI as you replace functionality.
Thus, you create an interface, IMS from MS, register that with your DI Container and then change your calling code to no longer work with a concrete instance of MS but IMS allowing the DI container to do its work.
Let us assume, for arguments sake that IMS is defined as:
interface IMS
{
public FunctionOne();
public HTTPFunction();
}
so that MS now implements that interface e.g.,
class MS : IMS
{
public FunctionOne()
{
//Do some work
}
public HTTPFunction()
{
//Make some HTTP calls
}
}
So you register MS interface (IMS) with DI container something like:
Container.Register<IMS, MS>("OldMS");
Thus you change in program.cs from
var msInstance = new MS();
to
var msInstance = Container.Resolve<IMS>("OldMS");
Testing should show that the program behaviour has not changed.
Next you wish to introduce AEO functionality for the one call in MS.
AEO inherits from abstract class EC, has several fields it receives by means of DI, and is set up to be received by DI as well.
You fail to mention whether AEO implements any additional methods or properties to those that it inherits from EC so I'll assume that it's registered with an interface IAEO e.g.,
Container.Register<IAEO, AEO>();
If not then please interpolate where necessary.
Next we create a wrapper class around MS functionality that implements the IMS interface e.g.,
class MSTwo : IMS
{
private IMS oldMs;
private IAEO aeo;
public MSTwo()
{
oldMS = Container.Resolve<IMS>("OldMS");
aeo = Container.Resolve<IAEO>();
}
public FunctionOne()
{
oldMS.FunctionOne();
}
public HTTPFunction()
{
aeo.SomeFunction();
}
}
This class you register with your DI Container e.g.,
Container.Register<IMS, MSTwo>("NewMS");
and it can then be resolved within program.cs
var msInstance = Container.Resolve<IMS>("NewMS");
Note: In the above examples, for simplicity, I've omitted any reference to DI through constructors, their registration with the DI Container nor there resolution at runtime as the syntax is often DI Container dependent.
Thanks to #Oliver Jacot-Descombes` comment, I found a working solution.
Before calling new MS(...) I used reflection to get an instance of AEO.
aeo = container.ResolveKeyed<EC>(MCType.AEO) as AEO;
and then passed aeo in to the new MS(...,aeo)
I am trying to understand Dependency Injection where usually everything is injected as either via Constructor or Property Injection.
So far I have understood that it basically revolves around interface to mock the class.
I am checking out Nop Commerce where I came across CustomerModelFactory which accepts couple of Domain class like CustomerSettings,DatetimeSettings etc..
Now when I check the DependencyRegistrar.cs class, I don't see how the dependency registration or even in the same class, I don't see the new instance of CustomerSettings created anywhere.
So my question is when we inject concrete class in constructor of class, where do we register it or how IOC container supply the instance?
CustomerModelFactory.cs
public partial class CustomerModelFactory : ICustomerModelFactory
{
// all below are concrete class
public CustomerModelFactory(AddressSettings addressSettings,
CaptchaSettings captchaSettings,
CatalogSettings catalogSettings,
CommonSettings commonSettings,
CustomerSettings customerSettings,
DateTimeSettings dateTimeSettings,
}
DependencyRegistrar.cs
public class DependencyRegistrar : IDependencyRegistrar
{
public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
{
builder.RegisterType<CustomerModelFactory>().As<ICustomerModelFactory>().InstancePerLifetimeScope();
}
}
I couldn't find where below is done:
CustomerSettings settings = new CustomerSettings();
or
CatalogSettings settings = new CatalogSettings();
How can I understand how this is working?
That's why DI does not really reduce complexity, instead, it hides complexity under surface and offload lifecycle management to another thing that you don't really know too much, as each DI framework is different. Anyway, that is another topic.
Here is to answer your question, ignore which DI framework, just think in general, there are 3 ways for you to get an instance of an object
Create the instance directly when you need it
CustomerSettings settings = new CustomerSettings();
Create the instance by Reflection when you need it
Type t = typeof(CustomerSettings);
CustomerSettings settings = Activator.CreateInstance(t) as CustomerSettings;
Cache all instances in a dictionary and look up when using the type name
something can be like this:
Dictionary<Type, object> lookup;
lookup.Add(typeof(CustomerSettings), new CustomerSettings()):
(This way does not generate a new instance though).
Now if you need the instance, you ask the dictionary to give it to you
lookup[typeof(CustomerSettings)]
This action, is called Resolved in many DI framework.
How does the DI framework find it though?
To do this, many DI framework will use reflection to find the matching type. There should always a process to register the types you want DI framework to resolve automatically. It means, you tell DI framework what type it needs to be aware, and then give it back to me when you look up using the type.
For example, you may see code like this:
container.Register<CustomerSettings>();
In this case, CustomerSettings is a class type, so DI knows how to create it when you need it.
However, if you are registering an interface
container.Register<ICustomerSettings, CustomerSettings>():
The above is one syntax to register interface and its concrete type. Basically, you tell DI, this is the type, and that is the implementation. So when you do this:
var setting = container.Resolve<ICustomerSettings>();
You will get an instance of CustomerSettings.
It will work if you have multiple implementations of the same interface, but you need some special handling. Different DI handles it differently.
Hopefully so far it makes a little sense.
Each DI framework has an IOC container, which acts like a dictionary. You register the type into there, and ask it to give it back.
There are more details, but I will not cover in here.
Concrete types are not automatically resolved by MS.DI; they need to be registered explicitly. NopCommerce, therefore, registers them inside its DependencyRegistrar class (on line 241):
//register all settings
var settings = typeFinder.FindClassesOfType(typeof(ISettings), false).ToList();
foreach (var setting in settings)
{
services.AddScoped(setting, serviceProvider =>
{
var storeId = DataSettingsManager.IsDatabaseInstalled()
? serviceProvider.GetRequiredService<IStoreContext>()
.GetCurrentStoreAsync().Result?.Id ?? 0
: 0;
return serviceProvider.GetRequiredService<ISettingService>()
.LoadSettingAsync(setting, storeId).Result;
});
}
I have added the dependency injections to the project. But when i create an instance by using new keyword, dependency injection doesn't work.
public class MyClass
{
ILoginTokenKeyApi _loginTokenKeyApi;
public MyClass(ILoginTokenKeyApi loginTokenKeyApi)
{
_loginTokenKeyApi = loginTokenKeyApi;
}
...
}
When i try to create an instance of MyClass, it wants a parameter to be constructed naturally.
Just like this :
MyClass mc = new MyClass(); // ERROR, it wants a parameter (but it is what i want)
I have to do :
MyClass mc = new MyClass(new LoginTokenKeyClass()); // this is not a good code for me
How i create an instance of MyClass without parameter because it has dependency injected.
But when i create an instance by using new keyword, dependency injection doesn't work.
That’s fundamentally how dependency injection works.
With dependency injection, you are simply not supposed to new up new objects. That’s the whole point of dependency injection and inversion of control. Instead of creating objects and managing those objects’ dependencies, you are depending on the framework to give you the dependencies you need without having you to care about where they actually come from and how they are constructed properly. So you are moving the responsibility to create the object up to the caller.
If you find yourself in need to create an object that has a dependency, then this is a clear sign that you are doing it wrong. A common reason for this is that you want to create the object in order to manage its lifetime, or because it is actually a data object that just happens to have some operations that needs other dependencies to work (e.g. an entity that has a “save” method). In the first case, you simply don’t do it like that. You just depend on it and let the framework manage the lifetime; if it has an incorrect lifetime, then you should reconfigure it with the DI container.
In the latter case where you have a data object with operations, you should split this up. You should just have a data object, without any logic, and then inject some manager service that is able to perform the operation on that data object for you.
For example in ASP.NET Core Identity, you have the User object which is just a normal entity without any logic. In order to e.g. add user roles or change the password, you rely on the user manager which you can inject. So the User object itself is without any dependencies.
I’d generally suggest you to read the dependency injection chapter of the ASP.NET Core documentation to understand how dependency injection works and how it is supposed to be used within the framework.
As mentioned in the comments, it is not clear what you trying to achieve, but in order to do DI in .Net Core you have to create an interface IMyClass, then let your class implement that interface,
public interface IMyClass {
void SampleMethod();
}
public class MyClass : IMyClass
{
ILoginTokenKeyApi _loginTokenKeyApi;
public MyClass(ILoginTokenKeyApi loginTokenKeyApi)
{
_loginTokenKeyApi = loginTokenKeyApi;
}
public void SampleMethod()
{
// method logic goes here...
var xx = _loginTokenKeyApi.WhatEver;
}
}
then register ILoginTokenProvider and IMyClass in startup.cs
services.AddTransient<ILoginTokenProvider, LoginTokenProvider>();
services.AddTransient<IMyClass, MyClass>();
finally inject IMyClass where you need it:
public class IndexModel : PageModel {
private readonly IMyClass _myClass;
public IndexModel(IMyClass myClass)
{
_myClass = myClass;
}
public void OnGet()
{
_myClass.SampleMethod();
}
}
btw, it is also possible to register and inject MyClass without implementing IMyClass interface, but I prefer to follow basic programming principals :)
There are two types of Dependency Injections.
Constructor Injection - which you dont want
Property Injection - In this - you expose Public Get/Set property of the Object you want to be injected. And then in your DI config file (like spring.net) you can assign values.
Another way you can do DepInjection is that in the param less constructor - you can get the Object by a Key/Name. Like in Spring.Net we would do:
var UtilityObject = Spring.ContextRegistry.GetContext().GetObject("MyUtilObject") as TheUtilityClass;
I think I'm missing a key part of how to actually use IoC/DI. I happen to be using the Unity container. I know how to setup a class to have it's dependencies injected and I also know how to make Unity register a type.
But what I don't know is how to actually then make use of these registrations.
So for example:
var container = new UnityContainer();
container.RegisterType<IRepository, XmlRepository>();
var service = new MyService(container.Resolve<IRepository>());
public interface IRepository
{
void GetStuff();
}
public class XmlRepository : IRepository
{
public void GetStuff()
{
throw new NotImplementedException();
}
}
public class MyService
{
private readonly IRepository _myRepository;
public MyService(IRepository repository)
{
_myRepository = repository;
}
}
Here I have a service layer which accepts a parameter of type IRepository. It's the container part that I seem to not be understanding.
Isn't the point of IoC/DI to be able to not have to manually resolve types every time I need to create an instance? In my code I'm getting the container to resolve a type, unless I'm misunderstanding how this is supposed to work, isn't the container supposed to somehow automatically (with reflection?) inject the dependency I told it to use when I registered the type? var service = new MyService(...) Is calling container.Resolve the correct way of doing this?
I've created a container, but how do I share this container amongst my project/code? This sort of relates to the first question. I had previously thought that there was a single place that you register types. So far the only way I can see how to get around this is to:
Keep registering types wherever I use them and end up with duplicated code
Pass the container around to every place I'm going to be resolving types
Neither of these ways are how I'd expect this to work
Isn't the point of IoC/DI to be able to not have to manually resolve types every time I need to create an instance?
No, that's the point of a DI Container, but there are drawbacks to using a container as well. Favour Pure DI over using a DI Container, as this will teach you how to use Dependency Injection using only first principles.
I've created a container, but how do I share this container amongst my project/code?
You don't. The DI Container should only be used in the Composition Root (if you use a DI Container at all).
Put your container setup in a module that runs when your program starts. You can call it from Main, for example. This is called a boot strapper.
See Dependency Injection with Unity for a good example of how to do this.
You don't need to do new MyService(container.Resolve<IRepository>()). To get an instance of MyService, just use container.Resolve<MyService>(); it will automatically resolves the dependencies for MyService.
I have a feeling this is just a misunderstanding on my part of DI in winforms.
I'm trying to implement Ninject into an existing winforms app. In Program.cs I am doing something similar to
IKernel kernel = new StandardKernel(new NinjectBindings());
Application.Run(kernel.Get<MainContainer>());
My NinjectBindings has
Bind<IFilterEngine>().To<FilterEngine>();
Then in a customer usercontrol (SearchResults.cs) in a form of the MainContainer form I am trying to use method injection like so
[Inject]
public void AddFilterEngine(IFilterEngine filterEngine)
{
_filterEngine = filterEngine;
}
The app compiles and runs fine however, my _filterEngine instance is null and the AddFilterEngine method is never called. Is this because SearchResults is not created with Ninject? It is hardcoded in its parent form. If so, I'm assuming every parent from this point needs to also be created with Ninject?
Injection only occurs when the instance is created through Ninject, i.e. by calling Kernel.Get<T>(), which is usually only done at the "topmost" point within your application or by Ninject creating this instance itself.
So unless you create your usercontrol by calling Kernel.Get<SearchResult>() (assuming the class is called SearchResult) using self-binding or by the container (as a constructor argument for example), your method will never get invoked, unfortunately.
You need to either use a field or a Property setter for Ninject to Inject your value on object creation.
[Inject]
public IFilterEngine FilterEngine { get; set; }
You can also pass it as a parameter to the constructor if you don't what this property to be public. This is the preferred method. Follow the examples on the Ninject website.