尚未注册“MyType”类型的服务。

18
我有一个通用的仓库架构,看起来像这样:
仓库
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
    }

    // [...]
}

当我在`repositoryFactory.GetRepository()`方法中调用`_provider.GetRequiredService()`时,我会得到上面注释中的错误。
`RepositoryFactory`正常传递,但是`UserRepository`没有被注册。我错过了什么?我尝试在构造函数之外调用`GetRepository`方法,并尝试将`AddScoped`更改为其他`Add`变体(如`Transient`和`Singleton`),但都没有成功。
2个回答

9

你正在依赖于实现而非接口的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未注册(并且如上所述-您也不应该解析它)。


我们两个同时在打我们的答案,但我认为我们基本上是在说同样的事情。这就是解决方案。 - jacobsowles
这是我的问题的解决方案,在.cshtml视图中,我实现了@inject MyService,但我应该使用@inject IMyService接口。 - Bob Kaufman

5
看起来我的问题与我对AddScoped的理解有关。查看文档,AddScoped中的两个类型参数是TServiceTImplementation。因此,在我的上面的Startup类中,我注册的SERVICEIRepository<ApplicationUser>,而不是ApplicationRepository。我注册的IMPLEMENTATIONApplicationRepository
为了解决这个问题,我将我的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>();

    // [...]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接