Below is my sample code. I have this class whose constructor takes an IConfigurationRoot parameter and uses it to set a private field:
public class MyClass
{
private IConfigurationRoot _configuration;
public class MyClass(IConfigurationRoot configuration)
{
// I believe this has been injected
_configuration = configuration;
}
}
Now I want to instantiate that class:
public class AnotherClass
{
private IConfigurationRoot _configuration;
private MyClass myclass;
public SomeMethod()
{
// My _configuration here gets null in the debugger
MyClass myclass = new MyClass(_configuration);
// Rest of method omitted...
}
}
How do I properly instantiated that class so that it doesn't end up being null?
Follow this process:
1.) What I have done is map a section of the AppSettings.json file to an object.
A.) Add the configuration settings to json file.
"MyConfiguration": {
"DBServer": "MyDBServer",
"DBName": "MyDatabase"
}
B.) Create a class to use strongly typed configurations.
public class MyConfiguration
{
public string DBServer { get; set;}
public string DBName { get; set;}
}
C.) Map the JSON configurations to the MyConfiguration object in the Startup class.
public class Startup
{
//Make sure you add this.
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
var configSection = Configuration.GetSection("MyConfiguration");
services.Configure<MyConfiguration>(configSection);
//Use one of the following.
Services.AddScoped<MyClass>();
Services.AddTransient<MyClass>();
Services.AddSingleton<MyClass>();
Services.AddInstance<MyClass>();
...
}
}
See this link for an explanation of the differences between
`AddSingleton()`
`AddScopped()`
`AddInstance()`
`AddTransient()`
2.) Change MyClass to have MyConfiguration object as a parameter of the MyClass constructor.
//add this using statement and corresponding package
//"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.1"
using Microsoft.Extensions.Options;
public class MyClass
{
private MyConfiguration _configuration;
public MyClass(IOptions<MyConfiguration> configuration)
{
_configuraiton = configuraiton.Value;
}
}
3.) Add MyClass as a parameter of the AnotherClass constructor. Dependency Injection will create the MyClass or reuse it depending on the scope of the object and how you setup that up in the Startup.ConfifureServices() method.
public class AnotherClass
{
private MyClass _myclass;
public AnoherClass(MyClass myclass)
{
_myclass= myclass;
}
public SomeMethod()
{
//Use myClass here and you don't need to instantiate it.
_myclass
....
}
}
You doing a couple of things.
1 - You are re-declaring your class variable myclass as a local variable in your SomeMethod. You should use the myclass variable you already declared as a class variable. To do that, make this line
MyClass myclass = new MyClass(_configuration);
Like this
myclass = new MyClass(_configuration);
2 - You are not instantiating your IConfigurationRoot, so it is null before inject it at all. You should be able to instantiate it however you want (ConfigurationBuilder like #Sach suggested, or _configuration = ConfigurationBuilder.Build() as #Eldho suggested), but you need to instantiate it before you inject it if you dont want it to be null.
Here, it would be best if you use an IOC container like Autofac or Unity or the built-in container in ASP.NET core(if you are using core). You would need to register your IConfigurationRoot interface and its implemented class with the IOC container. After this, inject your MyClass object using the IOC container(in the constructor, or in the method, as per your best scenario). This way, you would never face a problem.
Related
In a .NET Core 3.1 console application I want a Class that would have some parameters in constructor injected but some that I could assign manually. For example something like that but with IConfiguration Injected:
static void Main() {
var myObj1 = new MyClass(1);
var myObj2 = new MyClass(2);
}
public class MyClass {
public MyClass(IConfiguraiton config, int myVal)
{
}
}
I tried this with Ninject:
static void Main()
{
kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Get<MyClass>();
}
public class MyClass
{
public MyClass(IConfiguraiton config)
{
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
var configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.json").Build();
Bind<IConfiguration>().ToMethod(ctx => SetupConfiguration()).InSingletonScope();
Bind<MyClass>().ToSelf().InTransientScope();
}
}
I managed to make simple dependency injection, but haven't had any success making injection with parameters.
I've read a lot of people suggesting that it's better to pass parameters into methods of the class rather than constructor, however in my situation this isn't an option in addition I'm a software engineering student, and would like to learn how to do this, since it might be useful in some situations.
This is a situation where the Ninject.Extensions.Factory is useful, as it is made exactly for this situation. It does pull in the Factory dependency in addition to Castle.Core, as it uses DynamicProxy under the hood (as a SE student, playing with this library is a good idea for using the interceptor pattern).
To use it, you define a Factory interface like so:
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
Note that the Create method returns MyClass, and the argument(s) to the Create method match exactly in type and name to the arguments you wish to provide. The argument type(s) you want injected must be registered with the kernel. Unfortunately, it is easy to make a mistake here - if you specify a parameter that does not exist in the factory interface it is ignored, but if you forget one it will throw an exception when called.
Next, register IMyClassFactory like this: Bind<IMyClassFactory>().ToFactory(); and remove your binding for MyClass. Then wherever you need to create an instance, inject IMyClassFactory and call Create: kernel.Get<IMyClassFactory>().Create(2)
You can achieve the same result without using Ninject.Extensions.Factory by writing and registering your own implementation of IMyClassFactory, essentially doing the same thing that the code the Factory extension ends up emitting. A full sample is below using both methods based on commenting in/out the registration (note the output if you add .InSingletonScope() to the registration of IConfiguraiton - both approaches respect the binding scopes of Ninject).
internal class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Bind<IConfiguraiton>().To<Configuraiton>();
kernel.Bind<IMyClassFactory>().ToFactory();
//kernel.Bind<IMyClassFactory>().To<NinjectMyClassFactory>().InSingletonScope();
var factory = kernel.Get<IMyClassFactory>();
var one = factory.Create(1);
var two = factory.Create(2);
}
}
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
public class NinjectMyClassFactory : IMyClassFactory
{
public NinjectMyClassFactory(IResolutionRoot resolutionRoot)
{
ResolutionRoot = resolutionRoot;
}
private IResolutionRoot ResolutionRoot { get; }
public MyClass Create(int myVal)
{
return ResolutionRoot.Get<MyClass>(new ConstructorArgument("myVal", myVal));
}
}
public class MyClass
{
public MyClass(IConfiguraiton config, int myVal)
{
Console.Out.WriteLine("Created MyClass({0},{1})", config.MyNum, myVal);
}
}
public interface IConfiguraiton { int MyNum { get; } }
public class Configuraiton : IConfiguraiton
{
static int CreateCount;
public Configuraiton()
{
MyNum = Interlocked.Increment(ref CreateCount);
}
public int MyNum { get; }
}
I have installed the Microsoft Dependency Injection into a .NET Framework 4.8 class library. I have also reigster interface A to class A. The problem is that my class B that takes a object of interface A in construtor still demands it when I try to create the class? So how do I get the DI system to provide this object in a class Library where there is no real entry point?
public Class B
{
B(){InterfaceA}
}
public Class A : InterfaceA
{}
public MainClass
{
public void DoStuff()
{
DependencyContainer.Register();
var myB = new B();
}
}
public DependencyContainer
{
public void Register()
{
(new ServiceCollection()).AddTransient<InterfaceA, A>();
}
}
Regards
DI means that any depencencies will come (get injected) from the outside. The class itself won't even know that dependency injection is used. In your case, the classes should be rewritten to accept dependencies instead of creating them:
public Class B
{
public A MyA {get;}
public B(InterfaceA a)
{
MyA=a;
}
}
public Class A : InterfaceA
{}
public MainClass
{
public B MyB {get;}
public MainClass(B b)
{
MyB=b;
}
public void DoStuff()
{
MyB......;
}
}
The classes know nothing about DI. When asked for a MainClass instance with, eg services.GetRequiredService<MyClass>(), the DI container will create all the necessary instances and pass them to the classes.
The common pattern for all .NET Core libraries is to provide extension methods that can be used to register or configure their classes in the main application's Startup class or ConfigureServices delegate. To do that, all that's needed is the IServicesCollection interface from the Microsoft.Extensions.DependencyInjection.Abstractions package. There's no need to add the full DI package :
public static class MyLibServiceExtensions
{
public static IServicesCollection AddMyClasses(this IServicesCollection services)
{
services.AddTransient<ClassB>()
.AddTransient<InterfaceA,ClassA>()
.AddTransient<MainClass>();
return services;
}
}
This can be used now to register the classes, eg in a Console application :
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddMyClasses()
.AddHostedService<Worker>();
});
}
Or the Startup.ConfigureServices method of a web app:
public class Startup
{
public Startup(IWebHostEnvironment env)
{
HostingEnvironment = env;
}
public IWebHostEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMyClasses();
}
}
The classes will now be injected into any class generated by the DI container, eg a `Controller:
public class MyController:ControllerBase
{
public MyController(MyDbContext dbContext,MainClass main)
{
_db=dbContext;
_main=main;
}
}
OK, so dependency injection isn't magic. Your Register method is building a collection of services and throwing it away. You need to actually resolve your components from the container (I'm not saying directly, but the container has to be involved).
You should build an IServiceProvider from it using the BuildServiceProvider method:
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var b = serviceProvider.GetRequiredService<B>(); // constructs B and injects A
Probably you should do this in your Main method, and then inject B (or a Func to create B) into MainClass:
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<MainClass>();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
serviceCollection.AddTransient<Func<B>>(provider => () => provider.GetRequiredService<B>()); // factory method
var serviceProvider = serviceCollection.BuildServiceProvider();
// ask the container for MainClass and then call DoStuff
var mainClass = serviceProvider.GetRequiredService<MainClass>();
mainClass.DoStuff();
}
And then you could rewrite MainClass like this:
public class MainClass
{
private readonly B _bInstance;
private readonly Func<B> _bFactory = new Func<B>();
// if you want to create instances of B as and when, I'd suggest using a factory
// otherwise you can pass in a single instance
// I've done both here as an example
public MainClass(Func<B> bFactory, B bInstance)
{
_bInstance = bInstance;
_bFactory = bFactory;
}
public void DoStuff()
{
// create two instances of B
var b1 = _bFactory();
var b2 = _bFactory();
}
}
While I advocate for using a factory when you need to build instances on the fly, it is possible to inject IServiceProvider itself into your classes, and then call its GetRequiredService or GetService methods. The reason I don't do this is because it is considered to be an anti-pattern. Using a factory allows you to still make changes at the composition root (i.e. in Main) without editing everywhere that creates instances of B.
I am looking to use a variable Config instantiated in Program.cs to be able to use in other classes I have. As I understand, we need to use dependency injection, but not sure how to achieve.
Program.cs
public class Program
{
static IConfigurationRoot Config = null;
public static void Main(string[] args)
{
Config = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
}
}
TestClass.cs
public class TestClass
{
public void DoSomething()
{
// Now I need to use that instantiated Config object here.
}
}
You can either make Config static public, so it can be accessed anywhere in your application, or, if you want to use Dependency Injection, make your TestClass constructor ask for one IConfigurationRoot:
public TestClass(IConfigurationRoot config)
{
// do what you need
// save a reference to it on a local member, for example
}
Now every time you instantiate a new TestClass, you will have to pass by argument to its constructor the IConfigurationRoot object it will use. If that proves to be troublesome (e.g.: you instantiate TestClass a lot, in a lot of different places), then you might use a TestClassFactory:
public class TestClassFactory
{
public TestClass Get()
{
// Do your logic here to get a new TestClass object
// The IConfigurationRoot object that will be used to create TestClasses
// will be chosen here.
}
}
Also, if you don't want to use ASP.NET types directly, you may, as Crowcoder pointed out, make a config repository, as you would do for any database model. That repository would fetch configuration from a json file, for example.
Something like this:
public class ConfigurationRepository : IConfigurationRepository
{
public string GetBasePath()
{
// Read base path from config files
}
public string SetBasePath()
{
// Write base path to config files
}
}
And then you would use DI to pass IConfigurationRepository to your TestClass.
If Config is declared public static, then it can be accessed from other classes as Program.Config
I have a simple class which looks like this:
public class TestClass1
{
private string testString = "Should be set by DI";
public TestClass1(string testString)
{
this.testString = testString;
}
public string GetData()
{
return testString + DateTime.Now;
}
}
I want to inject it using the build-in DI in a simple ASP.NET core web app, but with the "testString" parameter set when initialising the Dependency Injection.
I've tried setting the following in startup.cs but it fails at runtime because TestClass1 doesn't have a parameterless constructor:
services.AddScoped(provider => new TestClass1("Success!"));
I suspect you just missed the cruical part of the code and your usage of the DI is just plain wrong, not the registration.
public class MyController
{
private readonly MyClass myClass;
public MyController()
{
// This doesn't work and do not involve DI at all
// It will fail because MyClass has no parameterles constructor
this.myClass = new MyClass();
}
}
The above won't work, because DI is no compiler magic that let you magically inject dependencies when calling new on the type.
public class MyController
{
private readonly MyClass myClass;
public MyController(MyClass myClass)
{
// This should work, because the IoC/DI Container creates the instance
// and pass it into the controller
this.myClass = myClass;
}
}
When you use DI/IoC you let the constructor generate and instantiate the objects, hence you never call new in your service classes. Just tell in the constructor that you need an instance of some type or it's interface.
Edit:
This used to work in previous versions (betas) of ASP.NET Core. Should still work, but limited to parameters:
public class MyController
{
public IActionResult Index([FromServices]MyClass myClass)
{
}
}
Imagine I have something I will create through a factory:
public sealed class MyClass
: IMyClass
{
private IMyDao MyDao { get; set; }
public MyClass(IMyDaoFactory factory)
{
MyDao = factory.MyDao;
}
}
This might resolve through a service as:
public sealed class MyService
: IMyService
{
private readonly IMyClass myClass;
public MyService(IMyDaoFactory factory)
{
myClass = new MyClass(factory);
}
}
That's easy to wire up in Unity as:
var container = new UnityContainer();
container.RegisterType<IMyService, MyService>();
container.RegisterType<IMyDaoFactory, MyDaoFactory>();
container.RegisterType<IMyClass, MyClass>();
Noting the registration of MyClass, how can I set Unity up so it will automatically register and resolve through the factory? I.e. then I no longer need:
myClass = new MyClass(factory);
Only:
this.myClass = myClass; (passed through the constructor
as IMyClass and resolved by Unity)
Hope that makes sense. Thanks in advance.
Try switching the constructor of MyService to requiring a single instance of IMyClass; Unity should automatically fill in the gaps there and instantiate based on the type signatures.
public MyService(IMyClass _myClass)
{
myClass = _myClass;
}
Although I'd also change the names up, but eh.