I'm using Ninject.MVC3.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<Repository>().To<Repository>();
}
Registering them like so in the App_Start.
It works just fine on controller that request this repository.
However I also have a few classes that need this repository.
[Inject]
public MemberShipService(Repository repository)
{
this.Repository = repository;
}
^Example from a class constructor.
I've tried constructor injection this simply gives me errors because it requests an argument for the constructor.
Property injection simply doesn't work.
Do I need to do something extra to make constructor or property injection work in asp.net mvc3? I haven't done any other configuration inside NinjectWebCommon other then the line I posted above.
You'll need to resolve an instance of the class using dependency resolver in order to use it, create an instance of your MemberShipService using:
var memberShipService =
DependencyResolver.Current.GetService(typeof(MemberShipService)) as MemberShipService;
That will bind your instance variable Repository using your constructor that you specified.
Related
So iv just been thrown into some new code at work and its in C#. Now I'm not very familiar with C# and there are some things I really don't understand and the main one is Injecting into methods.
Now there is a WebAPI and it has controller that uses a class named "LocalFileStorage" which is a dependency from another project, the constructor for that class looks like this.
public class LocalFileStorageHandler : IStorageHandler
{
*Bunch of private variables
public LocalFileStorageHandler(DbContext dbContext, IConfiguration configuration, ILogger<LocalFileStorageHandler> logger)
{ code here}
Now in the controller class every method that uses the LocalFileStorage gets it injected as a parameter. Here is a example:
public async Task<IActionResult> ApiMapper([FromBody] dynamic request, [FromServices] IStorageHandler storageHandler)
Also in the project startup.cs we can find this line:
services.AddScoped<IStorageHandler, LocalFileStorageHandler>();
Now my understanding is that for each separate request made the Addscoped makes sure that the method gets its own instance of LocalFileStorage handler. I also understand that the "[FromServices]" attribute causes this instance to be injected into the method. However the one thing I don't understand and cant find anywhere in the code is where the LocalFileStorage objects get their "In parameters" for their constructor?
As by my understanding each injected instance of LocalFileStorage should also receive the parameters:
DbContext dbContext, IConfiguration configuration, ILogger<LocalFileStorageHandler> logger
What am i missing here ?
Kind regards
The DI container injects the dependencies for you. So somewhere, the DbContext, IConfiguration and ILogger has been registered/setup.
Then when you use the FromServices attribute, the DI container will try to resolve the type for you and inject all dependencies (if they are registered, if not, an exception will be thrown)
IConfiguration and ILogger are usually setup when building the host. DbContext are (usually) registered by using the AddDbContext extension method.
Link to configuration for ILogger: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-6.0#logging-providers
Link to configuration for IConfiguration: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#default-configuration
Link to Dependency Injection fundamentals in ASP.Net Core : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0
I have an external ClassLibrary Project that needs to get session value set from HomeController in the Main Project.
Is there a simple way to accomplish this?
Or is there an alternative to transfer a value from HomeController to an external ClassLibrary?
You can use the IHttpContextAccessor class
For other framework and custom components that require access to
HttpContext, the recommended approach is to register a dependency
using the built-in dependency injection container. The dependency
injection container supplies the IHttpContextAccessor to any classes
that declare it as a dependency in their constructors.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddHttpContextAccessor();
services.AddTransient<IUserRepository, UserRepository>();
}
In the following example:
UserRepository declares its dependency on IHttpContextAccessor.
The dependency is supplied when dependency injection resolves the dependency chain and creates an instance of UserRepository.
.
public class UserRepository : IUserRepository
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRepository(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void LogCurrentUser()
{
var username = _httpContextAccessor.HttpContext.User.Identity.Name;
service.LogAccessRequest(username);
}
}
Don't forget to add services.AddHttpContextAccessor(); to make the dependency injection work.
The single-responsibility principle dictates that a class should do just one thing. While you can inject something like IHttpContextAccessor that then requires the class to have knowledge of concepts like HttpContext, Session, the fact that it's being used in a web environment in the first place, etc.
The correct approach is to inject or pass values. If the class needs a particular value from a session variable, access the session in your controller, where that logic actually belongs, and then pass only the value from the session to your external class.
If u use Abp template, the Abp application service ApplicationService already contains property AbpSession, you can inherit this class.
It has been well documented, how to inject dependencies into services.
Question: But is it (already) possible in ASP.NET Core 2.0 to have the system's DI mechanism automatically inject a service into a method or into a property?
Sidenote: In PHP-Symfony this pattern is called setter injection.
Example:
Say I have a common MyBaseController class for all controllers in my project and I want a service (e.g. the UserManager service) to be injected into MyBaseController that can be later accessed in all child controllers. I could use constructor injection to inject the service in the child class and pass it via base(userManager) to the parent. But having to perform this in all child constructors of all controllers is pretty tedious.
So I would like to have a setter in MyBaseController like this:
public abstract class MyBaseController : Controller
{
public UserManager<User> userManager { get; set; }
// system should auto inject UserManager here
public void setUserManager(UserManager<User> userManager) {
this.userManager = userManager;
}
}
...so I don't have to do the following in every child constructor just to pass the dependency to the parent:
public class UsersController : MyBaseController
{
public ChildController(UserManager<User> userManager) : base(userManager) {}
Update: The answer given here is what I want to achieve, however the question was asked for ASP.NET Core 1.0, I'm interested in whether any solutions have been added in ASP.NET Core 2.0.
In general it is good advice to avoid non constructor DI as it is considered a bit of an anti pattern, there is a good discussion about it in this related question.
With the default Microsoft.Extensions.DependencyInjection container in aspnet core, the answer is no, but you could swap to something more powerfull like autofac (which has property injection) if you are sure you really need this feature.
You can perform setter injection with the built-in DI container (Microsoft.Extensions.DependencyInjection) using Quickwire. Unlike Autofac, this is not a new DI container, it just extends the default one.
To make it work:
Add this to ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
// Activate controllers using the dependency injection container
services.AddControllers().AddControllersAsServices();
services.ScanCurrentAssembly();
// ...
// Register your other services
}
By default, ASP.NET Core will activate controllers by instantiating them directly without going through the DI container. Fortunately, this behaviour can easily be overridden to force ASP.NET Core to resolve controllers using dependency injection. This is what services.AddControllers().AddControllersAsServices() does.
ScanCurrentAssembly is necessary to get Quickwire to search for services declared in your assembly and register them (which will include your controllers).
Decorate your child controller with [RegisterService]
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
This will make your ChildController discoverable when ScanCurrentAssembly is called in step 1.
Decorate the setter
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
Now the UserManager property in your child controller will be automatically set from the dependency injection container.
You have two kind of DI
Mandatory, it's injection needed for object initialization then it's injection setted in constructor.
Optional, it's injection needed for action.
If DI is doing well, u can have unit test without injection system, if all injections are in ctor then you'll break every unit test, every time for nothing.
So all injections in ctor break open/close principle.
One more point is DI is for interface implementation or module public part, object under this implementation are initialized manually.
So setter is not bad because there are hidden by interface.
I use repository method to get all data from DB.
Here is the code of it:
public class ExperienceRepository
{
private readonly ToSeeDatabaseContext _context;
public ExperienceRepository(ToSeeDatabaseContext context)
{
_context = context;
}
public List<Experience> GetAllExperiences()
{
return _context.Experience.ToList();
}
}
I need to call GetAllExperience from controller.
So at first I need to declare repo as private property
I do it like this
private ExperienceRepository _exprepo = new ExperienceRepository();
But it says, it need
Severity Code Description Project File Line Suppression State
Error CS7036 There is no argument given that corresponds to the required formal parameter 'context' of 'ExperienceRepository.ExperienceRepository(ToSeeDatabaseContext)' TooSeeWeb C:\Users\EugeneSukhomlyn\source\Workspaces\TooSee\Too See Web\Too See Web\Too See Web\Controllers\ExperienceController.cs 14 Active
How I can solve it?
Since you are using dependency injection, the preferred way would be to inject the DB context to the repository.
You probably have already code similar to this in the ConfigureServices method of your Startup.cs file (or in the place where you configure your service collection if you are not using ASP.NET Core) to set up the context for dependency injection (if you don't you should add it):
services.AddDbContext<ToSeeDatabaseContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ToSeeDatabaseContext")));
Since your experience repository already accepts ToSeeDatabaseContext, it is already ready for dependency injection. Now you have to inform the DI framework about ExperienceRepository, so that it can inject it to its consumers. So in ConfigureServices you add:
services.AddTransient<ExperienceRepository, ExperienceRepository>();
Now can use dependency injection whenever you want to need the repository. In your consumer (eg. an ASP.NET page) you can use constructor injection to get a repository:
class MyExperienceConsumer {
private ExperienceRepository _exprepo;
public MyExperienceConsumer(ExperienceRepository exprepo) {
_exprepo = exprepo;
}
}
If your consumer is an ASP.NET page controller, this is all you need to do, since the MVC framework will create the controller for you and use DI to give you the repository. If you need to instantiate the consumer yourself you need to do so with the help a service provider from the DI framework, so that it can do its magic (assuming you have a service collection). When you use ActivatorUtilities, the DI framework will inject the repository into the constructor:
IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
MyExperienceConsumer consumer =
ActivatorUtilities.CreateInstance<MyExperienceConsumer>(serviceProvider);
In any case, you can use the DI framework to do the heavy lifting for you.
Your ExperienceRepository class have one constructor that requires a ToSeeDatabaseContext as parameter.
You are trying to create a instance ExperienceRepository with no parameters. The compiler can't find a constructor which doesn't take any parameters, producing the compiler error.
I am building an application which uses dependency injection following the options pattern design. I have a custom ORM class named DataManager. When I create an instance of DataManager I inject the connection string into the class as below.
public class DataManager : CommonDataManager {
private readonly ConnectionStrings _connectionStrings;
public DataManager(IOptions<ConnectionStrings> options) {
this._connectionStrings = options.Value;
}
When creating the DataManager object which parameter should I use? What should the initialisation code look like?
DataManager dm = new DataManager(?);
DI integration means that the DI engine is going to be responsible for object creation. So instead of directly initializing your class, you should rather do the following. Register also your DataManager with DI, so you can later instantiate it from serviceCollection:
In your ConfigureServices method add the following:
services.AddTransient<DataManager>();
Note, that you should decide the lifespan of your instance (I've chosen Transient here, but it's up to you - Singletone, Scoped, ...).
And then when you need to instantiate it, call as follows:
serviceProvider.GetRequiredService<DataManager>();
If, however, you want to go with your approach and want to instantiate the DataManager yourself, you should get the parameter from IoC container as follows:
DataManager dm = new DataManager(sp.GetRequiredService<IOptions<ConnectionStrings>>());
Note: that in both cases I assume that you've already registered the options with the DI in your Startup.ConfigureServices method.