我有一个通用的存储库架构,如下所示:
存储库
public interface IRepository<T> where T: class
{
IList<T> Get(Func<T, bool> where);
}
public abstract class Repository<T> : IRepository<T> where T: class
{
private readonly DbSet<T> _entity;
protected Repository(ApplicationDbContext dbContext)
{
_entity = dbContext.Set<T>();
}
public IList<T> Get(Func<T, bool> where)
{
return _entity.Where(where).ToList();
}
}
然后创建具体的实现:
UserRepository
public class UserRepository : Repository<ApplicationUser>
{
public UserRepository(ApplicationDbContext dbContext) : base(dbContext) {}
// Can add any other methods I want that aren't included in IRepository
}
我可能会提供相当多的服务,所以我不想让每一个服务单独进入控制器,我想我会尝试通过一个可以为我生成存储库的工厂。
RepositoryFactory
public interface IRepositoryFactory
{
T GetRepository<T>() where T : class;
}
public class RepositoryFactory : IRepositoryFactory
{
private readonly IServiceProvider _provider;
public RepositoryFactory(IServiceProvider serviceProvider)
{
_provider = serviceProvider;
}
public T GetRepository<T>() where T : class
{
return _provider.GetRequiredService<T>(); // ERROR: No service for type 'UserRepository' has been registered
}
}
现在,在设置依赖注入时,我注册了这样的服务:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// [...]
services.AddScoped<IRepository<ApplicationUser>, UserRepository>();
services.AddScoped<IRepositoryFactory, RepositoryFactory>();
// [...]
}
这在控制器中全部使用,如下所示:
控制器
public class HomeController : Controller
{
private readonly UserRepository _userRepository;
public HomeController(IRepositoryFactory repositoryFactory)
{
_userRepository = repositoryFactory.GetRepository<UserRepository>(); // ERROR: No service for type 'UserRepository' has been registered
}
// [...]
}
当我在_provider.GetRequiredService<T>()
方法中调用repositoryFactory.GetRepository<UserRepository>()
时,我在上面的评论中收到错误。
RepositoryFactory
即将到来,但UserRepository
尚未注册。我错过了什么?我尝试在构造函数之外调用GetRepository
方法,并且我尝试将AddScoped
更改为其他Add
变体(Transient和Singleton),但是没有果。
答案 0 :(得分:1)
你依赖于UserRepository
,这是实现而不是接口,这是不好的(假设你实际上已经在容器中注册了该接口)。相反,您需要依赖于接口:IRepository<ApplicationUser>
。所以改变你的工厂界面:
public interface IRepositoryFactory
{
IRepository<T> GetRepository<T>() where T : class;
}
实现:
public IRepository<T> GetRepository<T>() where T : class
{
return _provider.GetRequiredService<IRepository<T>>(); // ERROR: No service for type 'UserRepository' has been registered
}
和控制器:
public class HomeController : Controller
{
private readonly IRepository<ApplicationUser> _userRepository;
public HomeController(IRepositoryFactory repositoryFactory)
{
_userRepository = repositoryFactory.GetRepository<ApplicationUser>(); // ERROR: No service for type 'UserRepository' has been registered
}
// [...]
}
现在它不起作用,因为您在容器中注册了IRepository<ApplicationUser>
(实现为UserRepository
),但您尝试解析的UserRepository
未注册(并且如上所述 - 无论如何你不应该解决它。)
答案 1 :(得分:0)
看起来我的问题与我对AddScoped
的理解有关。查看文档,AddScoped
中的两个类型参数是TService
和TImplementation
。所以在上面的Startup课程中,我正在注册的 SERVICE 是IRepository<ApplicationUser>
,而不是ApplicationRepository
。我正在注册的 IMPLEMENTATION 是ApplicationRepository
。
要解决此问题,我更改了Startup
课程,说明UserRepository
是要注册的服务。
public void ConfigureServices(IServiceCollection services)
{
// [...]
// OLD: services.AddScoped<IRepository<ApplicationUser>, UserRepository>();
services.AddScoped<UserRepository>();
services.AddScoped<IRepositoryFactory, RepositoryFactory>();
// [...]
}
但是这种方法依赖于实现而不是抽象(接口),所以我更进一步,为UserRepository
类引入了一个接口,并在Startup
中注册了该接口。
<强> UserRepository 强>
public interface IUserRepository : IRepository<ApplicationUser>
{
void DoTheThing();
}
public class UserRepository : Repository<ApplicationUser>, IUserRepository
{
public UserRepository(ApplicationDbContext dbContext) : base(dbContext) {}
public void DoTheThing()
{
}
}
<强>启动强>
public void ConfigureServices(IServiceCollection services)
{
// [...]
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IRepositoryFactory, RepositoryFactory>();
// [...]
}