类型' MyType'没有服务已经注册

时间:2018-03-15 19:26:58

标签: c# .net dependency-injection .net-core asp.net-core-2.0

我有一个通用的存储库架构,如下所示:

存储库

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),但是没有果。

2 个答案:

答案 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中的两个类型参数是TServiceTImplementation。所以在上面的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>();

    // [...]
}