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...
Related
Is it good to resolve the dependencies dynamically like the way i'm doing. Everywhere, it is suggested to use Constructor injection. I really don't understand the drawbacks of doing it the way i'm doing it. Code snippets as below..
Employee.cs
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Department Department { get; set; }
}
IRepository.cs
public interface IRepository<TModel> where TModel : class
{
void Add();
IEnumerable<TModel> GetAll();
IEnumerable<TModel> GetByID();
}
Repository.cs
public class Repository<TModel> : IRepository<TModel> where TModel : class
{
public void Add()
{
throw new NotImplementedException();
}
public IEnumerable<TModel> GetAll()
{
throw new NotImplementedException();
}
public IEnumerable<TModel> GetByID()
{
throw new NotImplementedException();
}
}
EmployeeController.cs
public class HomeController : ApiController
{
IComponentContext _container;
public HomeController(IComponentContext container)
{
this._container = container;
}
public Repository<TModel> Using<TModel>() where TModel :class
{
var repository = _container.Resolve(typeof(IRepository<TModel>));
return repository as Repository<TModel>;
}
[HttpGet]
public IEnumerable<Employee> GetEmployees()
{
return Using<Employee>().GetAll();
}
}
Global.asax
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
var container = builder.Build(Autofac.Builder.ContainerBuildOptions.None);
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
}
Say i've 5 repositories, Constructor injection will resolve all the 5 dependencies for a request i make. I might not use 5 repositories for each and every request. SO i thought of resolving dependencies dynamically by passing the type like i'm doing it in Using<TModel>(). Any suggestions would be appreciated..!! Thank you...!!
Refrain from using the container directly inside your application components; this leads to all kinds of troubles such as maintainability and testability issues. Directly resolving instances from within application code is a well-known anti-pattern known as Service Locator.
As a first refactoring, you can instead apply the Unit of Work pattern. A Unit of Work allows access to underlying repositories. For instance:
public interface IUnitOfWork
{
IRepository<TModel> Repository<TModel>();
}
public sealed class HomeController : ApiController
{
private readonly IUnitOfWork _unitOfWork;
public HomeController(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
}
[HttpGet]
public IEnumerable<Employee> GetEmployees()
{
return this._unitOfWork.Repository<Employee>().GetAll();
}
}
Within the Composition Root (where it is allowed to access the container), we can now create an IUnitOfWork implementation that resolves repositories dynamically:
private sealed class AutofacUnitOfWork : IUnitOfWork
{
private readonly IComponentContext _container;
public AutofacUnitOfWork(IComponentContext container)
{
this._container = container;
}
public IRepository<TModel> Repository<TModel>()
{
return _container.Resolve<IRepository<TModel>>();
}
}
This pattern simplifies your application components considerably and prevents downsides that the Service Locator anti-pattern typically causes.
Although applying the Unit of Work pattern might be a useful step into the right direction, an even better approach is to skip the Unit of Work directly and simply inject a required repository directly into application components:
public sealed class HomeController : ApiController
{
private readonly IRepository<Employee> _employeeRepository;
public HomeController(IRepository<Employee> employeeRepository)
{
this._employeeRepository = employeeRepository;
}
[HttpGet]
public IEnumerable<Employee> GetEmployees()
{
return this._employeeRepository.GetAll();
}
}
Say i've 5 repositories, Constructor injection will resolve all the 5 dependencies for a request i make. I might not use 5 repositories for each and every request.
Note that from a performance perspective, you should typically not be concerned whether dependencies are used or not. Autofac is in most cases fast enough and it is unlikely that this will actually cause any performance problems in your production systems.
From a design perspective however you should be more worried if a class has many dependencies, while methods just use a few of them. This means that the methods in the class have little cohesion. This is an indication that the class should be split up into multiple smaller classes; it has multiple responsibilities.
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>>
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(...);
}
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();
}
}
}
My question is as follows:
I have a base controller (ASP.Net MVC controller) called ApplicationController, and I want all my controller to inherit from it. this base controller has a ILogger property, marked with a [Dependency] attribute. (yes, I know I should use constructor injection, I'm just curious about this attribute).
I created the container, registered types, changed the default factory, everything is fine. the problem is that when I try to use my Logger property in the derived controller, it's not resolved.
what am I doing wrong? why doesn't the container resolves the base class dependencies when creating the derived controller?
code samples:
ApplicationController:
public class ApplicationController : Controller
{
[Dependency]
protected ILogger _logger { get; set; }
}
derived controller:
public class HomeController : ApplicationController
{
public HomeController()
{
}
public ActionResult Index()
{
_logger.Log("Home controller constructor started.");
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
Unity controller factory:
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(Type controllerType)
{
return _container.Resolve(controllerType) as IController;
}
}
Global.asax.cs sample:
protected void Application_Start()
{
_container = new UnityContainer();
_container.RegisterType<ILogger, Logger.Logger>();
UnityControllerFactory factory = new UnityControllerFactory(_container);
ControllerBuilder.Current.SetControllerFactory(factory);
RegisterRoutes(RouteTable.Routes);
}
I'm quite new to Unity, so maybe I did something wrong.
thanks,
Ami.
AFAIK, Unity will only resolve public properties. Therefore your protected property will not be resolved.
I'm not sure if this is related, but usually, I avoid having namespaces and classes with the same name (in your case, Logger.Logger), for I had problems with this in the past. But that may be not the problem.
I'm also not sure if the [Dependency] attribute works for derived types. If you change it for constructor injection, does this still not work? Something like:
public class ApplicationController : Controller
{
protected ILogger _logger { get; set; }
public ApplicationController(ILogger logger)
{
this._logger = logger;
}
}
and
public class HomeController : ApplicationController
{
public HomeController(ILogger logger) : base(logger)
{
}
public ActionResult Index()
{
_logger.Log("Home controller constructor started.");
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
and the rest just the same. The code looks ok.
I'm fairly unexperienced with unity as well, but I think you need to register your HomeController with the contsaner, not the logger.
I had the same issue, and fixed it by changing the ILogger to public. This is with an ASP.NET MVC2 project in VS2010, .NET 4. It makes sense, logically, since Unity isn't creating a proxy class or anything, it's just setting properties that it has access to, and has a mapping for - hence public only.