I'm trying to understand dependency injection in ASP.NET MVC CORE.
All examples are the same, they show to register HttpContextAccessor
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
Then the class that wants to access it:
public class UserService : IUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public bool IsUserLoggedIn()
{
var context = _httpContextAccessor.HttpContext;
return context.User.Identities.Any(x => x.IsAuthenticated);
}
}
But then, when i actually want to create an instance of UserService, it asks for the httpContextAccessor object in constructor, where do i get that from?
When using dependency injection, you are not supposed to actually create any service yourself. To consume your UserService, you should just inject that somewhere as well.
Typically, the flow in ASP.NET Core for your application code starts in a controller. So if you want to use the UserService inside of a controller action, you should inject it into the controller:
public class ExampleController : Controller
{
private readonly IUserService _userService;
public ExampleController(IUserService userService)
{
_userService = userService;
}
public IActionResult Index()
{
var isLoggedIn = _userService.IsUserLoggedIn();
// …
return View();
}
}
So you don’t create an instance yourself using new but instead you rely on the dependency injection system to provide you with an instance.
You just need to make sure to register the service inside of the ConfigureServices:
services.AddTransient<IUserService, UserService>();
This principle holds regardless of where you are within your application. Since the entry point is always being created by the system, you are always inside of a dependency injection context, so you can just depend on things which have dependencies themselves (which again could have more dependencies etc).
I would strongly suggest you to read the chapter on dependency injection of the documentation, as it covers the idea very well. It also explains what the different lifetimes mean.
in DI, you normally dont need to create Instance by yourself. Instead you need to register your implemented services to the DI service container and then call it inside your constructor.
This way you eliminates the need for manual instance creation.
services.AddScoped<IMyService, MyService>();
then
class MyConsumerClass
{
private readonly IMyService _myService;
MyConsumerclass(IMyService myService)
{
_myService = myService;
}
}
In this way, you don't need to care about what services is needed to be initialized (parameterized) into your constructor.
Related
In the ValuesController, I'm calling method GetUsers of a class TestRepo to get list of all the users from the database. To do that I had to pass in the _context to TestRepo() like
var testRepo = new TestRepo(_context);
return testRepo.GetUsers();
How do I avoid passing _context to class TestRepo. Ideally, I want _context to be available to me in TestRepo and I don't want to pass _context in TestRepo. What is the right way of doing this?
ValuesController.cs
public class ValuesController : ControllerBase
{
private readonly ApplicationDBContext _context;
public ValuesController(ApplicationDBContext context)
{
_context = context;
}
// GET: api/<ValuesController>
[HttpGet]
public IEnumerable<User> Get()
{
var testRepo = new TestRepo(_context);
return testRepo.GetUsers();
}
}
TestRepo.cs
public class TestRepo
{
private readonly ApplicationDBContext _context;
public TestRepo(ApplicationDBContext context)
{
_context = context;
}
public IEnumerable<User> GetUsers()
{
return _context.Users.ToList(); ;
}
}
You can use dependency injection. .NET supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. Dependency injection in .NET is a built-in part of the framework, along with configuration, logging, and the options pattern.
A dependency is an object that another object depends on.
When you register your DbContext in the app you add it to the DI-container and then your controller can resolve a new instance of ApplicationDBContext for you. But you can add other dependencies to the DI-container and inject it as a dependency via constructor parameter.
For example in your case if you use Startup.cs you can add TestRepo as scoped dependency:
public void ConfigureServices(IServiceCollection services)
{
// you already has this 2 lines of code somewhere
services.AddDbContext<ApplicationDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers();
// use AddScoped to add TestRepo to DI-container
services.AddScoped<TestRepo>();
}
or if you use modern style application builder use next syntax:
// you already has this 2 lines of code somewhere
builder.Services.AddDbContext<ApplicationDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddControllers();
// use AddScoped to add TestRepo to DI-container
builder.Services.AddScoped<TestRepo>();
After registering the DbContext and the TestRepo class in container, you can use the TestRepo in the ValuesController to get an instance TestRepo class with injected DbContext:
public class ValuesController : ControllerBase
{
private TestRepo _testRepo;
public ValuesController(TestRepo testRepo)
{
_testRepo = testRepo;
}
[HttpGet]
public IEnumerable<User> Get()
{
return _testRepo.GetUsers();
}
}
Also you can inject your dependency directly to the action method with FromServices attribute:
public IEnumerable<User> Get([FromServices] TestRepo testRepo)
{
return testRepo.GetUsers();
}
Note that dependency injection is related to interfaces and abstractions, so it is important to use it when you use DI. It's a part of SOLID principles. Interfaces provide a level of abstraction from the concrete implementation, making it easier to swap out implementations and allowing for greater flexibility and reusability and easier testing with mocks.
Finally understanding the life cycle of dependency injection is very important in ASP.Net (Core) applications. Transient objects are always different; a new instance is provided to every controller and every service. Scoped objects are the same within a request, but different across different requests. Singleton objects are the same for every object and every request. You can learn more in .net tutorial "Use dependency injection in .NET".
In Azure Functions (v3 on NetCore3.1) using SimpleInjector 5.3, I've followed the guidance here using IHttpClientFactory instead of a typed client that depends on a MS DI-constructed HttpClient, but SimpleInjector can't resolve the IHttpClientFactory either.
public class FooClient
{
private IHttpClientFactory _clientFactory;
private FooClientConfig _config;
public FooClient(IHttpClientFactory clientFactory, FooClientConfig config)
{
_clientFactory = clientFactory;
_config = config;
}
}
public class Startup : FunctionsStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
var container = new Container();
container.RegisterInstance<FooClientConfig>(new FooClientConfig() { ApiKey = Configuration.GetValue<string>("FooApiKey") });
container.Register<FooClient>();
services.AddSimpleInjector(container);
}
}
public class FooCommandHandler
{
private readonly FooClient _fooClient;
public FooCommandHandler (FooClient client)
{
_fooClient = fooClient;
}
}
I then use the container to activate a Command/Query mediator but the container can't find an IHttpClientFactory to use for the FooClient.
SimpleInjector.ActivationException: 'The configuration is invalid. Creating the instance for type FooClient failed. The constructor of type FooClient contains the parameter with name 'clientFactory' and type IHttpClientFactory, but IHttpClientFactory is not registered. For IHttpClientFactory to be resolved, it must be registered in the container. Verification was triggered because Container.Options.EnableAutoVerification was enabled. To prevent the container from being verified on first resolve, set Container.Options.EnableAutoVerification to false.'
I guess my question is, where am I supposed to setup the Auto-cross-wiring for simpleinjector? I thought the call to services.AddSimpleInjector(container); would make the MS DI registered IHttpClientFactory available to the container and thus to the registrations therein.
Following the integration guide that Steven has put together over at the SimpleInjector docs VERY CAREFULLY, and using IHttpClientFactory instead of any typed clients I was finally able to get this to work - it is not pretty though.
I suggest that if you're using anything other than the Http factory pattern in the old Azure Functions ecosystem (non-isolated) you'll be fine. It's the cross-wiring of certain services like HttpClient under the hood that makes this a total mess. Hope this helps anyone else facing the same issue.
I'm new with .Net Core (using 3.1) and using Dependency injection. I was able to setup NLog in the Web API Controller but now I'm trying to get NLog to work in a separate business class following the basics of what I did in the API Controller. I keep get errors about the logger being NULL and when I put a break point on the _logger and _config, sure enough they are NULL. I'm not sure what I'm missing here.
This is my Business class and I thought I had it setup correctly but obviously not.
public class ShiftBLL
{
private static IConfiguration _config;
private static ILogger<ShiftBLL> _logger;
public ShiftBLL(ILogger<ShiftBLL> logger, IConfiguration config)
{
_config = config;
_logger = logger;
}
public static List<AppsShift> GetShifts(string station, string shiftDate)
{
_logger.LogInformation("Staion: {0} | ShiftDate: {1}", station, shiftDate);
*code removed for clarity. The app breaks on the initial call of _logger.
}
}
FIX
I removed the "static" from the ShiftBLL class as well as from the local parameters. Then I had to create an object of ShiftBLL in my Controller passing in the logger and config from the controller where I have DI working into the ShiftBLL. I ended up with this in my Controller:
ShiftBLL BLL = new ShiftBLL(_logger, _config);
listShifts = BLL.GetShifts(station, shiftDate);
Here is my updated ShiftBLL:
public class ShiftBLL
{
private IConfiguration _config;
private readonly ILogger _logger;
public ShiftBLL(ILogger logger, IConfiguration config)
{
_config = config;
_logger = logger;
}
public List<AppsShift> GetShifts(string station, string shiftDate)
{
_logger.LogInformation("Staion: {0} | ShiftDate: {1}", station, shiftDate);
}
Still getting my head wrapped around Dependency Injection.
When using DI, the DI container will insert the parameters for all dependencies when needed.
I will try to explain with a simplified example:
public class MyClass
{
public MyClass(ShiftBLL shiftBll)
{ .. }
}
When resolving MyClass, the DI container will do:
Find all needed dependencies for creating an instance of MyClass - in this case: ShiftBLL
Find all needed dependencies for creating ShiftBLL, in this ILogger and IConfiguration
Find the registrations for ILogger and IConfiguration (as those are interfaces), and dependencies etc.
Create a instance of ILogger and IConfiguration (via the registrations), create instance of ShiftBLL by injecting the instances into the constructor
Create a instance of MyClass and inject in instance of ShiftBLL.
So with this chain, all your constructor dependencies are created.
But if you're are using static methods in ShiftBLL, you are not sure if the constructor of ShiftBLL (with the ILogger) is ever invoked - so the ILogger field could be null. .
So to fix this case you could do:
Make the method non-static, or
Send all dependencies (ILogger) to the static method as parameter
You mixed up static methods calls and Dependency Injection. I would say to avoid the use of static methods whenever possible, anyway when you are using static methods you cannot access dependencies that are injected through dependency injection. For instance you cannot access _logger from GetShifts because you don't have an instance of ShiftBll and the fact that you call it statically means that its constructor is never called.
This is a working example of how to design classes and their dependencies and how to register them.
public class AController : Controller {
private readonly ILogger<AController> _logger;
private readonly ShiftBll _shiftBll;
public AController(ILogger<AController> logger, ShiftBll shiftBll) {
_logger = logger;
_shiftBll = shiftBll;
//I'm pretty sure you didn't inject the dependency here
//you preferred to use a static reference, but it is not correct in this case
}
public ActionResult AnAction() {
var shifts = _shiftBll.GetShifts("aStation", "aShiftDate");
}
}
public class ShiftBLL
{
private readonly IConfiguration _config; //not static
private readonly ILogger<ShiftBLL> _logger; //not static
public ShiftBLL(ILogger<ShiftBLL> logger, IConfiguration config)
{
_config = config;
_logger = logger;
}
public List<AppsShift> GetShifts(string station, string shiftDate) //not static
{
_logger.LogInformation("Staion: {0} | ShiftDate: {1}", station, shiftDate);
*code removed for clarity. The app breaks on the initial call of _logger.
}
}
.NET Core DI automatically registers controllers, but you have to manually register your own services. To do this go in the ConfigureServices method of your Startup.cs and add
services.AddScoped<ShiftBll>();
now you can use ShiftBll from AController.
I have no extensive experience in testing, but I'm setting up a Singleton instance injection for a class I created. However, I don't know how to call that class. If I do call, I need constructors. If I create an additional empty constructor, the dependencies will appear as null.
I have spent a few days looking for it in the documentation, but it only shows examples of how to inject. I cannot find how to instantiate the class afterwards.
Also, I see some examples, but many of them are using MVC Controllers, which are instantiated automatically by the framework.
Connector.cs
public class Connector
{
private IConfiguration _configuration;
public Connector(IConfiguration configuration) {
_configuration = configuration;
}
public Connector() {
}
public string DoSomething() {
//return Something related to _configuration
}
}
startup.cs
public void ConfigureServices(IServiceCollection services)
{
//Other default config
services.AddSingleton(new Connector(Configuration));
}
HomeController.cs
public IActionResult Index()
{
var x = (new Connector()).DoSomething(); //This will fail as _configuration is not injected
return View();
}
How can I call Connector with the injected Configuration? Am I missing any dependency resolving? Am I calling the class incorrectly?
I hope somebody can shed some light on this.
The idea behing DI container is that you don't need to handle object creation in your methods. Your HomeController also doesn't need to know if Connector is actually a singleton or not.
You just inject the dependency to your constructor.
Since you have configured it to be a singleton, DI container will resolve Connector to the same instance every time.
public class HomeController
{
private readonly Connector _connector;
public HomeController(Connector connector)
{
_connector = connector;
}
public IActionResult Index()
{
var x = _connector.DoSomething();
// ...
}
I have implemented an adapter that implement IServiceProvider and returned it from the ConfigureServices method in the Startup. class:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var kernel = new StandardKernel();
var container = new NinjectComponentContainer(kernel);
// ...
return ServiceProviderFactory.Create(container, services);
}
However, my implementation doesn't seem to be used everywhere. I even tried to override the IHttpContextAccessor to return a modified HttpContext:
public HttpContext HttpContext {
get
{
var result = _httpContextAccessor.HttpContext;
result.RequestServices = _serviceProvider;
return result;
}
set => _httpContextAccessor.HttpContext = value;
}
To test whether I could get to my implementation I used a filter in order to see what the HttpContext.RequestServices would return:
public class AuthorizationTestAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var service = context.HttpContext.RequestServices.GetService(typeof(IAccessConfiguration));
}
}
The type returned by context.HttpContext.RequestServices is:
My main issue was trying to get registered components resolved in the constructor of a filter but it always seems to fail saying the component is not registered. However it does seem to work when using the TypeFilter attribute:
[TypeFilter(typeof(RequiresSessionAttribute))]
However, my attribute does inherit from TypeFilter:
public class RequiresSessionAttribute : TypeFilterAttribute
{
public RequiresSessionAttribute() : base(typeof(RequiresSession))
{
Arguments = new object[] { };
}
private class RequiresSession : IAuthorizationFilter
{
private readonly IAccessConfiguration _configuration;
private readonly IDatabaseContextFactory _databaseContextFactory;
private readonly ISessionQuery _sessionQuery;
public RequiresSession(IAccessConfiguration configuration,
IDatabaseContextFactory databaseContextFactory, ISessionQuery sessionQuery)
{
Guard.AgainstNull(configuration, nameof(configuration));
Guard.AgainstNull(databaseContextFactory, nameof(databaseContextFactory));
Guard.AgainstNull(sessionQuery, nameof(sessionQuery));
_configuration = configuration;
_databaseContextFactory = databaseContextFactory;
_sessionQuery = sessionQuery;
}
I did come across this question but there is no definitive answer.
Any ideas on how to correctly provider a custom implementation of the IServiceProvider interface that will be used throughout the solution?
Even though Microsoft states that it is possible to replace the built-in container it appears as though it is not quite this simple, or even possible.
As stated by Steven in his very first comment, if you choose to use your container of choice, you should run them side-by-side.
The guidance from Microsoft suggests changing the ConfigureServices in the Startup class from this:
public void ConfigureServices(IServiceCollection services)
{
// registrations into services
}
to the following:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var container = new YourContainer(); // Castle, Ninject, etc.
// registrations into container
return new YourContainerAdapter(container);
}
However, there are a number of issues with this since there are already framework registrations in services that we do not necessarily know how to re-register in our own container. Well, there is a descriptor so if our container supports all the various methods then it is actually possible to re-register all the components. The various DI containers have different mechanisms when it comes to registration and service resolution. Some of them have a very hard distinction between the two making it quite tricky at times to accommodate a "common" solution.
My initial idea was to provide an adapter that accepts both my own container as well as the services collection from which I would then get the built-in service provider by calling services.BuildServiceProvider(). In this way I could attempt to resolve from the built-in provider and then, if the resolving bit failed, attempt to resolve from my own container. However, it turns out that the .net core implementation does in fact not use the returned IServiceProvder instance.
The only way I could get this to work was to wire up my own container and use it to resolve my controllers. That could be done by providing an implementation of the IControllerActivator interface.
In this particular implementation I was fiddling with Ninject although I typically prefer Castle but the same applies to any DI container:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
}
public class ControllerActivator : IControllerActivator
{
private readonly IKernel _kernel;
public ControllerActivator(IKernel kernel)
{
Guard.AgainstNull(kernel, nameof(kernel));
_kernel = kernel;
}
public object Create(ControllerContext context)
{
return _kernel.Get(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
_kernel.Release(controller);
}
}
In order to register the controller types I did my DI wiring in the Configure method since I have access to the IApplicationBuilder which can be used to get to the controller types:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
var kernel = app.ApplicationServices.GetService<IKernel>();
// kernel registrations
var applicationPartManager = app.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var controllerFeature = new ControllerFeature();
applicationPartManager.PopulateFeature(controllerFeature);
foreach (var type in controllerFeature.Controllers.Select(t => t.AsType()))
{
kernel.Bind(type).ToSelf().InTransientScope();
}
applicationLifetime.ApplicationStopping.Register(OnShutdown);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(
options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
);
app.UseMvc();
}
This worked swimmingly for the controllers but resolving "filters" was still a problem given that they use the IFilterFactory on the filter itself to implement a factory method:
public IFilterMetadata CreateInstance (IServiceProvider serviceProvider);
Here we can see that the IServiceProvider implementation is provided in order to resolve any depedencies. This applies when using the TypeFilterAttribute or when defining new filters that inherit from TypeFilterAttribute as I have in my question.
This mechanism is actually a very good example of the difference between "Inversion of Control" and "Dependency Injection". The control lies with the framework (inversion) and we have to provide the relevant implementations. The only issue here is that we are not able to hook in properly since our provided IServiceProvider instance is not passed to the CreateInstance method which then results in a failure when attempting to create an instance of the filter. There are going to be a number of ways to fix this design but we'll leave that to Microsoft.
In order to get my filters working I decided to go the "cross-wiring" route as alluded to by Steven by simply registering the depedencies required by my filters in the services collection also:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
services.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>();
services.AddSingleton<IDatabaseGateway, DatabaseGateway>();
services.AddSingleton<IDatabaseContextCache, ContextDatabaseContextCache>();
// and so on
}
Since I do not have many dependencies in my filter it works out OK. This does mean that we have "duplicate" registrations that we need to be careful of depending on how the instances are used.
I guess another option may be to forego your DI container of choice and use only the built-in container.