Injecting a collection with Ninject - c#

Let's suppose I have the following class:
public class AsyncEntityManager<E> : EntityManager<E>, IAsyncEntityManager<E>
where E : IPersistableEntity
{
public AsyncEntityManager(ICollection<IPersistenceStrategy<E>> strategies, ILogger logger) : base(strategies, logger) { }
}
How can I inject the collection in this case?
This is what I tried:
internal class PersistenceModule : ApplicationModule
{
public override void Load()
{
Kernel.Bind<ICollection<IPersistenceStrategy<User>>>().ToMethod(c => new IPersistenceStrategy<User>[] {
(IPersistenceStrategy<User>)c.Kernel.GetService(typeof(DynamoDBStrategy<User>))
});
Kernel.Bind<IAsyncEntityManager<User>>().To<AsyncEntityManager<User>>();
}
}
However, the collection is being injected with no elements. It is not null, but it has no elements at all in it. THe ILoggeer, nevertheless, is being injected just fine.

For anyone interested, it seems Ninject can handle multipible bindings to the same interface:
Kernel.Bind<IPersistenceStrategy<User>>().To<DynamoDBStrategy<User>>();
Kernel.Bind<IPersistenceStrategy<User>>().To<SQLServerStrategy<User>>();
This will be injected as a IPersistenceStrategy<User>[], which is then casted to ICollection<IPersistenceStrategy<User>>

Related

.Net Core Dependency Injection Get different instance generated by Two Factory Methods

I have two static classes with single static factory method for each.
public static class First
{
public IMyService Factory()
{
return IMyService()
{
//configure with Configs
};
}
}
public static class Second
{
public IMyService Factory()
{
return IMyService()
{
// configure with different Configs
};
}
}
The following would make provider return an instance when asked for:
services.AddSingleton(mb =>
{
var myService= First.Factory();
return myService;
});
How do I call different factories when need to get an instance with different configs?
If it's a one-time decision (app startup) than you should extract your config as a dependency:
in appsettings.json:
"mysettings":{"bla":"val1"}
somewhere in project:
public class mysettings { public string bla {get;set; }
in myservice constructor:
public myservice(IOptions<mysettings> settings) { ... }
in startup.cs:
services.Configure<mysettings>(this.Configuration.GetSection("mysettings"));
services.AddSingleton<Imyservice, myservice>();
Like this you inject the settings and your service will be instantiated with those that are specified in the appsettings.json
If you need to deside "live" which settings to use:
public interface IMyServiceFactory{
IMyService Create(MySettings settings);
}
Than you inject IMyServiceFactory to the class where you want to use IMyService and instantate it there with the right settings. Or even:
public interface IMyServiceFactory{
IMyService Create1();
IMyService Create2();
}
In any case you just register the factory in startup:
services.AddSingleton<IMyServiceFactory, MyServiceFactory>();
Somehow your client code or the bootstrapping code needs to express what kind of implementation is needed. You could implement it the following way:
public Interface IReqeust
{
// Some code
}
public class HttpRequest : IRequest
{
// Implementation
}
public class TcpRequest : IRequest
{
// Implementation
}
One way could be to offer multiple methods. You can still hide the configuration but some implementation details leak into your client code.
public Interface IRequestFactory
{
IRequest CreateHttpRequest();
IRequest CreateTcpRequest();
}
public class RequestFactory : IRequestFactory
{
// Implementation
}
Another solution would be to determine whats needed while constructing your factory.
public Interface IRequestFactory
{
IRequest CreateRequest();
}
public class RequestFactory : IRequestFactory
{
private IConfigReader configReader;
public RequestFactory(IConfigReader configReader)
{
this.configReader = configReader;
}
public IRequest CreateRequest()
{
var currentProtocoll = configReader.GetCurrentProtocoll();
if(currentProtocoll is HTTP)
return new HttpRequest();
else
return new TcpRequest();
}
}
I would not recommend your solution with more factories. At least not with what you wrote so far.

What is the best way to implement Dependency Injection in Base Controller

I have the follow trouble, in my base controller i do dependency injection. And i have a class child with implementation of base controller and i need pass the constructor. So my doubt is, my way to implementation of dependency injection is correctly?
If no, what is the best way to do this?
I use unity to implementate D.I, and my ide is VS2017 web api 2.
Follow this code i using:
Base controller or parent controller:
public class BaseController : ApiController
{
public string[] includes = null;
private readonly IFiltroServico servico;
public BaseController(IFiltroServico _servico)
{
servico = _servico;
}
}
Base controller to generics types implements Base Controller:
public abstract class BaseController<E, R, F> : BaseController
where E : class
where R : class
where F : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
}
Child controller:
public abstract class BaseController<R> : BaseController
where R : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
//services of controller;
}
You don't need to define the private field servico over and over again as it is already preset in the base controller. Just define it as protected readonly in the base class and use it in the childs.
Other than that your code is fine.
It is perfectly reasonable that a child has the same dependency parameters in the constructor as it inherits behavior of the base class that is most likely relying on the dependency.
Another option would be to use property injection in the base class but you need to add a unity specific attribute to the property. I don't like that as you bind your code directly to Unity.
Have you seen https://simpleinjector.org/index.html
check out git from https://github.com/simpleinjector/SimpleInjector
It is one of the best Inversion of Control library (IOC).
Only thing you need to do is register all your services and types.
using SimpleInjector;
static class Program
{
static readonly Container container;
static Program() {
// 1. Create a new Simple Injector container
container = new Container();
// 2. Configure the container (register)
container.Register<IOrderRepository, SqlOrderRepository>();
container.Register<ILogger, FileLogger>(Lifestyle.Singleton);
container.Register<CancelOrderHandler>();
// 3. Verify your configuration
container.Verify();
}
static void Main(string[] args)) {
// 4. Use the container
var handler = container.GetInstance<CancelOrderHandler>();
var orderId = Guid.Parse(args[0]);
var command = new CancelOrder { OrderId = orderId };
handler.Handle(command);
}
}
Once you register all your types and services you can inject those services where ever you want
public class CancelOrderHandler {
private readonly IOrderRepository repository;
private readonly ILogger logger;
private readonly IEventPublisher publisher;
// Use constructor injection for the dependencies
public CancelOrderHandler(
IOrderRepository repository, ILogger logger, IEventPublisher publisher) {
this.repository = repository;
this.logger = logger;
this.publisher = publisher;
}
public void Handle(CancelOrder command) {
this.logger.Log("Cancelling order " + command.OrderId);
var order = this.repository.GetById(command.OrderId);
order.Status = OrderStatus.Cancelled;
this.repository.Save(order);
this.publisher.Publish(new OrderCancelled(command.OrderId));
}
}
public class SqlOrderRepository : IOrderRepository {
private readonly ILogger logger;
// Use constructor injection for the dependencies
public SqlOrderRepository(ILogger logger) {
this.logger = logger;
}
public Order GetById(Guid id) {
this.logger.Log("Getting Order " + order.Id);
// Retrieve from db.
}
public void Save(Order order) {
this.logger.Log("Saving order " + order.Id);
// Save to db.
}
}
Let me know if you have any queries, Thanks.

Castle Windsor injecting controller with two instances of same interface

I have my controller like this
public class MyController : Controller
{
private IEntityRepository accountsRepo;
private IEntityRepository dataRepo;
public MyController(IEntityRepository accs, IEntityRepository data)
{
accountsRepo = accs;
dataRepo = data;
}
.....
}
And I installed container this way:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IEntityRepository>()
.ImplementedBy<AccountsRepository>()
.Named("accs")
.LifestyleTransient(),
Component.For<IEntityRepository>()
.ImplementedBy<DataRepository>()
.Named("data")
.LifestyleTransient());
}
}
Also I have facilities setted up:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<DbContext>()
.ImplementedBy<AccountsContext>()
.LifestylePerWebRequest(),
Component.For<DbContext>()
.ImplementedBy<DataContext>()
.LifestylePerWebRequest());
}
}
}
...and installed:
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<PersistenceFacility>();
}
}
So when I'm using my controller both parameters are injected with AccountsRepository instance (which was registered first). Of course I wanna see "data" being DataRepository respectively. Please, explain me proper way to deal with this kind of injection.
EDIT
As #roman suggested I have implemented generic repositories:
public interface IRepository : IDisposable
{
void SaveChanges();
void ExecuteProcedure(String procedureCommand, params SqlParameter[] sqlParams);
}
public interface IEntityRepository<T> : IRepository
{
T Context { get; set; }
DbSet<TEntity> Set<TEntity>() where TEntity : class;
}
public class AccountsRepository : IEntityRepository<AccountsContext>
{
public AccountsContext Context { get; set; }
public AccountsRepository(AccountsContext c)
{
Context = c;
}
public DbSet<TEntity> Set<TEntity>() where TEntity : class
{
return Context.Set<TEntity>();
}
public virtual void ExecuteProcedure(String procedureCommand, params SqlParameter[] sqlParams)
{
Context.Database.ExecuteSqlCommand(procedureCommand, sqlParams);
}
public virtual void SaveChanges()
{
Context.SaveChanges();
}
public void Dispose()
{
if (Context != null)
Context.Dispose();
}
}
DataRepository looks the same way, my be at some point I will decide to have just one concrete class EntityRepository, but it not relevant to exceptions I receiving.
So after cosmetic interfaces changes my contreller become:
public class HomeController : Controller
{
private IEntityRepository<AccountsContext> accountsRepo;
private IEntityRepository<DataContext> dataRepo;
public HomeController(IEntityRepository<AccountsContext> accs, IEntityRepository<DataContext> data)
{
accountsRepo = accs;
dataRepo = data;
}
....
}
Also I have changed installer code:
container.Register(
Component.For<IEntityRepository<AccountsContext>>()
.ImplementedBy<AccountsRepository>()
.LifestyleTransient(),
Component.For<IEntityRepository<DataContext>>()
.ImplementedBy<DataRepository>()
.LifestyleTransient());
And now during controller resolving proccess
return (IController) kernel.Resolve(controllerType);
I catching
Can't create component 'MyMVCProj.DAL.AccountsRepository' as it has dependencies to be satisfied.
'MyMVCProj.DAL.AccountsRepository' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
Castle.MicroKernel.Handlers.HandlerException: Can't create component 'MyMVCProj.DAL.AccountsRepository' as it has dependencies to be satisfied.
'MyMVCProj.DAL.AccountsRepository' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
But I have installed AccountsContext in facility logic.
EDIT++
According to #Roman suggestion I have tweaked my facility this way:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<DbContext>()
.ImplementedBy<AccountsContext>()
.Named("accctx")
.LifestylePerWebRequest(),
Component.For<DbContext>()
.ImplementedBy<DataContext>()
.Named("datactx")
.LifestylePerWebRequest());
}
}
and also repositories installler:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IEntityRepository<AccountsContext>>()
.ImplementedBy<AccountsRepository>()
.Named("accs‌​")
.LifestyleTransient()
.DependsOn(Dependency.OnComponent(typeof (DbContext), "accctx")),
Component.For<IEntityRepository<DataContext>>()
.ImplementedBy<DataRepository>()
.Named("data")
.LifestyleTransient()
.DependsOn(Dependency.OnComponent(typeof (DbContext), "datactx")));
}
}
This is the exception I get now:
Can't create component 'accs‌​' as it has dependencies to be satisfied.
'accs‌​' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
But trying to solve this brute forcing the code I ended with working solution, just installing concrete implementations of DBContext:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<AccountsContext>().LifestylePerWebRequest(),
Component.For<DataContext>().LifestylePerWebRequest());
}
}
And kernel's components now are:
AccountsContext PerWebRequest
AccountsRepository / IEntityRepository<AccountsContext> Transient
DataContext PerWebRequest
DataRepository / IEntityRepository<DataContext> Transient
And before they were:
AccountsContext / DbContext PerWebRequest
AccountsRepository / IEntityRepository<AccountsContext> Transient
DataContext / DbContext PerWebRequest
DataRepository / IEntityRepository<DataContext> Transient
So the new questions are:
Have I did all stuff idiomatically?
Why this behaviour - there already was AccountContext with little mention of it dependencies.
The fact that you expect two instances of same interface, yet you require different behavior for them (by injecting them to two different parameters), implies - in my opinion - that they shouldn't be the same interface, because they have different roles, or responsibilities. It would make sense to me more, if IEntityRepository was a generic class and then you would require in MyController two different generic interface types:
public class MyController(IEntityRepository<Account> acc, IEntityRepository<Data> data)
Nevertheless, If you still want to do that kind of thing, I suggest you use a CollectionResolver that will allow MyController class to get an IEnumerable. That way you'll get both instances, but it'll be up to you to select the appropriate one to use depending on your needs, which I'll stress again, I think is the wrong approach for this.
To use CollectionResolver you need to register it with the Windsor container like this:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
And then, MyController will look like this:
public class MyController(IEnumerable<IEntityRepository> repositories)
{
accountsRepo = repositories.Where(...);
dataRepo = repositories.Where(...);
}

WebAPI. Dependency injection with Ninject in case of inheritance

I'm pretty new to ASP.NET WebApi project, but hopefully I'll put everything straight enough. After creating couple CRUD Controllers a brilliant idea come to my mind - write generic base CRUD-web-API controller for all of them and do not mess with rewriting same code.
After successful implementation of such class I faced problem with dependency resolving which is still working fine for non-generic/-inherited controllers.
Simple request (GET, POST, etc.) gives:
Type 'UsersController' does not have a default constructor","ExceptionType":"System.ArgumentException"
Default constructor without injections works fine. Obviously I have a problem with Ninject configuration.
public abstract class BaseCRUDController<T> : ApiController where T : class, IClientEntity
{
private readonly Repository<T> _repo;
private readonly IDbContextDataProvider _context;
// With this ctor everything works well
public BaseCRUDController()
{
this._context = new ModelContext();
this._repo = new Repository<T>(this._context);
}
// Injection is not working ((
public BaseCRUDController(IDbContextDataProvider context)
{
this._context = context;
this._repo = new Repository<T>(context);
}
And concrete Controller for User entity:
public class UsersController : BaseCRUDController<User>
{
UsersController(IDbContextDataProvider context) : base(context) { }
UsersController() : base() { }
}
And Ninject config itself:
public class DataProviderModule : NinjectModule
{
public override void Load()
{
this.Bind<IDbContextDataProvider>().To<ModelContext>().InSingletonScope();
}
}
public class NinjectResolver
{
// Instantinate Ninject dependencies resolver
public static System.Web.Http.Dependencies.IDependencyResolver GetConfiguredDependencyResolver()
{
IKernel kernel = new StandardKernel(new DataProviderModule());
System.Web.Http.Dependencies.IDependencyResolver njResolver = new NinjectResolver(kernel);
return njResolver;
}
}
And Application_Start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
var config = GlobalConfiguration.Configuration;
config.DependencyResolver = NinjectResolver.GetConfiguredDependencyResolver();
WebApiConfig.Register(config);
What am I doing wrong here?
NOTE: This approach works well if I have:
public class UsersController : ApiController
{
UsersController(IDbContextDataProvider context)
{
....
}
...
Oh.. I've spent hours trying different approaches. It was madness. And the funny part here is that Ninject is working well and code is correct except one accessibility modifier. Adding public modifier to UsersController ctor fixed the issue.
public class UsersController : BaseCRUDController<User>
{
public UsersController(IDbContextDataProvider context) : base(context) { }
...
PS. Write your code carefully...

Problem with Setter injection with Structuremap

I am creating an instance of a type scoped to HTTPContextScoped. I am trying to figure out how to inject this specific instance into a property of the same type into an attribute that I don't have control over.
I want to inject the specific instance of UnitOfWork into a property of IUnitOfWork type in an attribute (see code below)
Here is my ObjectFactory.Initialize() method of the part that I am referring to:
ObjectFactory.Initialize(x =>
{
//...
//additional content
//...
x.For<IUnitOfWork>()
.HttpContextScoped()
.Use(context => new UnitOfWork(
context.GetInstance<ISessionFactory>()));
x.SetAllProperties(context =>
{
context.Matching(p =>
p.DeclaringType == typeof(UnitOfWorkAttribute));
context.OfType<IUnitOfWork>();
});
Attribute Class:
public class UnitOfWorkAttribute : ActionFilterAttribute {
public IUnitOfWork UnitOfWork { get; set; }
public UnitOfWorkAttribute() {
Order = 0;
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
UnitOfWork.Begin();
}
public void OnActionExecuted(ActionExecutedContext filterContext) {
UnitOfWork.End();
}
}
I was trying to follow one of Jeremy Miller's examples of using criteria to do so, but I am not doing something right.
Any thoughts of what I am doing incorrectly?
NOTE It does create the UnitOfWork instance as I use it else where, but I am specifically not correctly (or at all) injecting this attribute's property with that instance (or any for that matter).
Try solving this problem by creating a factory for IUnitOfWork objects. Since the lifetime of unit of work instances must be controlled explicly (since you are doing Begin and End, controlling them yourself is much more logical, and adheres the principle of least surprise.
Here is an example of what you can do:
public interface IUnitOfWorkFactory
{
IUnitOfWork NewUnitOfWork();
}
public class MyController : Controller
{
private readonly IUnitOfWorkFactory factory;
public MyController(IUnitOfWorkFactory factory)
{
this.factory = factory;
}
public void Operation()
{
using (var work = new this.factory.NewUnitOfWork())
{
work.Begin();
// do some interesting stuff here.
work.End();
}
}
}

Categories