I am using Ninject for IoC. I have the following classes.
// Repository
public class EFProductRepository : IProductRepository, IUnitOfWorkRepository
{
private IUnitOfWork unitOfWork;
private EFDbContext efDbContext;
public EFProductRepository(IUnitOfWork uow)
{
unitOfWork = uow;
efDbContext = new EFDbContext();
}
//
}
// Controller
public class ProductController : Controller
{
private IUnitOfWork unitOfWork;
private IProductRepository productRepository;
public ProductController(IUnitOfWork uow, IProductRepository repo)
{
unitOfWork = uow;
productRepository = repo;
}
}
Currently my ninject bindings are as follow which assign new instance of the concrete class for the interface.
ninjectKernel.Bind<IUnitOfWork>().To<UnitOfWork>();
ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
using my ninject controller factory, I need to inject same instance of the IUnitOfWork class to the ProductController and EFProductRepository. Please guide me.
Related
I'm hitting the error in the title when running this setup code:
Program.cs:
builder.Services.AddDbContext<TDBContext>(opt => opt.UseInMemoryDatabase("My"));
// Can't work out how to wire up the Repository?
//builder.Services.AddScoped<IRepository>(p => new TDBContext());
//builder.Services.AddScoped<IRepository, Repository>();
builder.Services.AddScoped(typeof(IRepository), typeof(Repository<>));
//builder.Services.AddScoped(typeof(IRepository), typeof(Repository<TDBContext>));
builder.Services.AddScoped<IMyService, MyService>();
var app = builder.Build(); //ERROR HERE!
Service and Repository:
public class MyService : IMyService
{
private readonly IRepository _repository;
public MyService(IRepository repository)
{
_repository = repository;
}
}
public class Repository<TDBContext> : IRepository where TDBContext : DbContext
{
protected DbContext dbContext;
public Repository(DbContext context)
{
dbContext = context;
}
public async Task<int> CreateAsync<T>(T entity) where T : class
{
this.dbContext.Set<T>().Add(entity);
return await this.dbContext.SaveChangesAsync();
}
//.....
}
public class TDBContext : DbContext
{
public TDBContext(DbContextOptions<TDBContext> options)
: base(options)
{
}
public virtual DbSet<MyTransaction> Transactions { get; set; } = null!;
public TDBContext()
{
}
}
I've tried a few suggestions found on here shown as code comments but no luck. Can someone please clarify how I wire up the Repository and get the DI to load in the DbContext?
Check the repository constructor. The container does not know how to handle DbContext as dependency when resolving the repository.
Did you mean to use the generic argument type instead?
Also the naming of the generic parameter might cause confusion.
public class Repository<TContext> : IRepository where TContext : DbContext {
protected DbContext dbContext;
public Repository(TContext context) {
dbContext = context;
}
public async Task<int> CreateAsync<T>(T entity) where T : class {
this.dbContext.Set<T>().Add(entity);
return await this.dbContext.SaveChangesAsync();
}
//.....
}
And the registration will need to use the closed type
//...
builder.Services.AddScoped<IRepository, Repository<TDBContext>>();
//...
I am trying to implement a repository pattern for learning purposes in a project. I am using MVVM Light to register interfaces and am trying to inject into a view model.
I have removed all the other repositories for ease of reading and only included the RuleRepository.
View Model Locator
The code breaks when trying to register the IUnitOfWork and gives the error - Type not found in cache: YAI.BomConfigurator.Core.Context.BomConfiguratorContext.
Note: Not sure if I need to register the IRepository interface here?
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
}
SimpleIoc.Default.Register<LoginViewModel>();
}
public LoginViewModel LoginViewModel
{
get
{
return ServiceLocator.Current.GetInstance<LoginViewModel>();
}
}
}
LoginViewModel
Here is where I try and inject an IUnitOfWork into the view model.
public class LoginViewModel : ViewModelBase
{
private readonly IUnitOfWork _UnitOfWork;
public LoginViewModel(IUnitOfWork unitOfWork)
{
_UnitOfWork = unitOfWork;
}
}
IUnitOfWork
public interface IUnitOfWork : IDisposable
{
IRuleRepository Rules { get; }
int Complete();
}
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private readonly BomConfiguratorContext _context;
public IRuleRepository Rules { get; private set; }
public UnitOfWork(BomConfiguratorContext context)
{
_context = context;
}
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
RuleRepository
public class RuleRepository : Repository<Rule>,IRuleRepository
{
public RuleRepository(BomConfiguratorContext context)
: base(context)
{
}
}
I copied a lot of this from Mosh Hamedani youtube video and tried adding in the bit where we inject into the constructor of the view model. I am a newbie at dependency injection and IOC containers so not to sure what exactly I am doing wrong here.
If someone could give me a good explanation as to what I need to change etc. that would be great. I know many people believe the Unit of Work / Repository Pattern is an anti pattern but I am not concerned about that, this is purely for learning purposes.
Thank you for any suggestions!
You are not only injecting an instance of UnitOfWork into LoginViewModel, you are also injecting an instance of BomConfiguratorContext into UnitOfWork when you instantiate UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly BomConfiguratorContext _context;
public IRuleRepository Rules { get; private set; }
// here you inject a BomConfiguratorContext, but none is registered in the VM Locator
public UnitOfWork(BomConfiguratorContext context)
{
_context = context;
}
...
}
So you need to change your ViewModelLocator to also register BomConfiguratorContext:
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
}
SimpleIoc.Default.Register<LoginViewModel>();
// Missing something like this (not sure what interface it implements...)
SimpleIoc.Default.Register<IConfiguratorContext, BomConfiguratorContext>();
}
When playing around with AutoMapper I was wondering whether the following is possible to implement like this (haven't been able to set it up correctly).
Base Service:
public class BaseService<T, IEntityDTO> : IService<T, IEntityDTO> where T : class, IEntity
{
private IUnitOfWork _unitOfWork;
private IRepository<IEntity> _repository;
private IMapper _mapper;
public BaseService(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_repository = unitOfWork.Repository<IEntity>();
_mapper = mapper;
}
public IList<IEntityDTO> GetAll()
{
return _mapper.Map<IList<IEntityDTO>>(_repository.GetAll().ToList());
}
}
Concrete Service:
public class HotelService : BaseService<Hotels, HotelsDTO>, IHotelService
{
private IUnitOfWork _unitOfWork;
private IRepository<Hotels> _hotelsRepository;
private IMapper _mapper;
public HotelService(IUnitOfWork unitOfWork, IMapper mapper) : base(unitOfWork, mapper)
{
_unitOfWork = unitOfWork;
_hotelsRepository = unitOfWork.Repository<Hotels>();
_mapper = mapper;
}
}
Current mappings:
public class AutoMapperProfileConfiguration : Profile
{
protected override void Configure()
{
CreateMap<Hotels, HotelsDTO>().ReverseMap();
}
}
I'm kindly clueless on how the mapping should be done. Anyone any advice or is this just not the way to go?
You can specify DTO type in BaseService as generic parameter:
public class BaseService<T, TDTO> : IService<T, TDTO>
where T : class, IEntity
where TDTO : class, IEntityDTO
{
private IRepository<T> _repository;
...
...
public IList<TDTO> GetAll()
{
return _mapper.Map<IList<TDTO>>(_repository.GetAll().ToList());
}
}
Managed to solve my problem with the following line of code which looks up the mapping of the passed entity to the basecontroller.
public List<TDTO> GetAll()
{
var list = _repository.GetAll().ToList();
return (List<TDTO>)_mapper.Map(list, list.GetType(), typeof(IList<TDTO>));
}
Using Ninject DI, I have implemented two interfaces that I instantiate from my MVC controllers. For example:
public class MyController : Controller
{
private readonly IUnitOfWork _UnitOfWork;
private readonly IAssetService _AssetService;
public MyController(IUnitOfWork unitOfWork, IAssetService assetService)
{
this._UnitOfWork = unitOfWork;
this._AssetService = assetService;
}
// Controller actions etc.
}
In my Ninject module I have created the following bindings:
public class DomainModule : NinjectModule
{
public override void Load()
{
Bind<IUnitOfWork>()
.To<SqlUnitOfWork>()
.InRequestScope()
.WithConstructorArgument("connectionString", "MyDb.Database");
Bind<IAssetService>()
.To<FileSystemAssetService>()
.WithConstructorArgument("rootPath", "C:\\DataStore");
}
}
I now want to inject the IUnitOfWork instance into my IAssetService so I have considered making this a property of IAssetService and modifying my controllers as follows:
public class MyController : Controller
{
private readonly IUnitOfWork _UnitOfWork;
private readonly IAssetService _AssetService;
public MyController(IUnitOfWork unitOfWork, IAssetService assetService)
{
this._UnitOfWork = unitOfWork;
this._AssetService = assetService;
this._AssetService.UnitOfWork = this._UnitOfWork;
}
// Controller actions etc.
}
but I wondered if there was a better/cleaner way of doing this using a different DI technique - ideally I would like to add the IUnitOfWork to the AssetService constructor?
Then why not simply inject the IUnitOfWork into the AssetService?
public class FileSystemAssetService : IAssetService
{
private readonly IUnitOfWork unitOfWork;
private readonly string rootPath;
public FileSystemAssetService(IUnitOfWork unitOfWork, string rootPath)
{
this.unitOfWork = unitOfWork;
this.rootPath = rootPath;
}
}
I'm using StructureMap in ASP .Net MVC 4 and I have got the following Interface and implemented class in my project infrastructure :
public interface IUnitOfWork
{
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
public void Commit()
{
// Track all changes in database
}
}
My HomeController is used the IUnitOfWork interface as constructor parameter :
public class HomeController
{
IUnitOfwork unitOfWork;
public HomeController(IUnitOfwork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
}
How can I inject IUniOfWork interface to overloaded HomeController class as parameter?
You must perform the following steps:
Remove and uninstall any configurations and packages for StructureMap.
Install structurmap.mvc4 from nuget
Configure your IoC container as :
x.For(IUnitOfWork).Use(UnitOfWork)