为啥我的通用服务出现“无法实例化实现类型”错误?

Posted

技术标签:

【中文标题】为啥我的通用服务出现“无法实例化实现类型”错误?【英文标题】:Why am I getting the error "Cannot instantiate implementation type" for my generic service?为什么我的通用服务出现“无法实例化实现类型”错误? 【发布时间】:2017-08-16 16:57:37 【问题描述】:

我有一个通用存储库,我已经在我的 WEB API 控制器中实例化了一段时间没有问题。

这是我的控制器过去的样子:

[Route("api/[controller]")]
public class EmployeesController : Controller

    private IGenericRepository<Employee> _empRepo;

    public EmployeesController(IGenericRepository<Employee> employeeRepo)
    
        _empRepo = employeeRepo;
    

    // GET: api/employees
    [HttpGet]
    public async Task<IEnumerable<Employee>> GetEmployeesAsync(
            string firstName = null, string lastName = null)
    
        //return await _empRepo.GetAll().Include("Organization").Include("PayPlan").Include("GradeRank").Include("PositionTitle").Include("Series").Include("BargainingUnit")
        //    .Where(e => (string.IsNullOrEmpty(firstName) || e.FirstName.Contains(firstName))
        //        && (string.IsNullOrEmpty(lastName) || e.LastName.Contains(lastName))
        //    )
        //    .ToListAsync();

        return await _empRepo.GetAllIncluding(
                a => a.Organization,
                b => b.PayPlan,
                c => c.GradeRank,
                d => d.PositionTitle,
                e => e.Series,
                f => f.BargainingUnit)
            .Where(e => (string.IsNullOrEmpty(firstName) || e.FirstName.Contains(firstName))
                && (string.IsNullOrEmpty(lastName) || e.LastName.Contains(lastName))
            )
            .ToListAsync();
    

    // GET api/employees/5
    [HttpGet("id", Name = "GetEmployeeById")]
    public async Task<IActionResult> GetEmployeeByIdAsync(long id)
             
        //var employee = await _empRepo.Find(id).Include("Organization").Include("PayPlan").Include("GradeRank").Include("PositionTitle").Include("Series").Include("BargainingUnit").SingleAsync();
        var employee = await  _empRepo.GetSingleIncludingAsync(id,
            a => a.Organization,
            b => b.PayPlan,
            c => c.GradeRank, 
            d => d.PositionTitle,
            e => e.Series,
            f => f.BargainingUnit);

        if (employee == null)
        
            return NotFound();
        
        else
        
            return new ObjectResult(employee);
        
    

    // PUT api/employees/id
    [HttpPut("id")]
    public async Task<IActionResult> PutEmployeeAsync([FromBody] Employee emp)
    
        var employee = await _empRepo.UpdateAsync(emp);
        if (employee == null)
        
            return NotFound();
        

        await _empRepo.SaveAsync();
        return new ObjectResult(employee);
    

我们会像这样在 StartUp 中配置 DI:

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

现在我刚刚重构并尝试在控制器和通用存储库之间放置一个服务层。

这是我在 StartUp 中的第二条 DI 线:

services.AddScoped(typeof(IGenericService<>), typeof(IGenericService<>));

所以现在我有这两条 DI 线:

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddScoped(typeof(IGenericService<>), typeof(IGenericService<>));

以下是我当前的代码:

从通用回购开始:

public enum FilteredSource

    All,
    GetAllIncluding,


public class GenericRepository<T> : IGenericRepository<T>
    where T: BaseEntity

    protected readonly ApplicationDbContext _context;
    protected DbSet<T> _dbSet;

    public GenericRepository(ApplicationDbContext context)
    
        _context = context;
        _dbSet = context.Set<T>();
    

    // no eager loading
    private IQueryable<T> All => _dbSet.Cast<T>();

    #region FIXME : DELETE
    // FIXME: Delete and use ALL instead.
    public IQueryable<T> GetAll() => _dbSet.AsQueryable();

    // FIXME: Delete and use GetSingleIncludingAsync instead.
    public IQueryable<T> Find(long id) =>
        _dbSet.Where(e => e.Id == id).AsQueryable();
    #endregion

    // eager loading
    private IQueryable<T> GetAllIncluding(
        params Expression<Func<T, object>>[] includeProperties) =>
         includeProperties.Aggregate(All, (currentEntity, includeProperty) => currentEntity.Include(includeProperty));

    // no eager loading
    public async Task<T> GetSingleIncludingAsync(long id)
    
        return await _dbSet.SingleOrDefaultAsync(e => e.Id == id);
    

    /// <summary>
    /// Takes in a lambda selector and let's you filter results from GetAllIncluding and All.
    /// </summary>
    /// <param name="selector">labmda expression to filter results by.</param>
    /// <param name="getFilteredSource">All or GetAllIncluding as the method to get results from.</param>
    /// <param name="includeProperties">array of eager load lamda expressions.</param>
    /// <returns></returns>
    public async Task<IEnumerable<T>> GetFiltered(
        Expression<Func<T, bool>> selector, FilteredSource filteredSource,
        Expression<Func<T, object>>[] includeProperties = null)
    
        var results = default(IEnumerable<T>);
        switch (filteredSource)
        
            case FilteredSource.All:
                results = All.Where(selector);
                break;
            case FilteredSource.GetAllIncluding:
                results = GetAllIncluding(includeProperties).Where(selector);
                break;
        
        return await results.AsQueryable().ToListAsync();
    

    // eager loading
    public async Task<T> GetSingleIncludingAsync(
        long id, params Expression<Func<T, object>>[] includeProperties)
    
        IQueryable<T> entities = GetAllIncluding(includeProperties);
        //return await Filter<long>(entities, x => x.Id, id).FirstOrDefaultAsync();
        return await entities.SingleOrDefaultAsync(e => e.Id == id);
    

    public async Task<T> InsertAsync(T entity)
    
        if (entity == null)
        
            throw new ArgumentNullException($"No nameof(T)  Entity was provided for Insert");
        
        await _dbSet.AddAsync(entity);
        return entity;
    

    public async Task<T> UpdateAsync(T entity)
    
        T entityToUpdate = await
            _dbSet.AsNoTracking().SingleOrDefaultAsync(e => e.Id == entity.Id);
        if (entityToUpdate == null)
        
            //return null;
            throw new ArgumentNullException($"No nameof(T)  Entity was provided for Update");
        

        _dbSet.Update(entity);
        return entity;
    

    public async Task<T> DeleteAsync(T entity)
    
        _dbSet.Remove(entity);
        return await Task.FromResult(entity);
    

    public Task SaveAsync() => _context.SaveChangesAsync();

接口定义:

public interface IGenericRepository<T>
    where T : BaseEntity

    #region FIXME : DELETE
    // FIXME: Delete and use ALL instead.
    IQueryable<T> GetAll();

    // FIXME: Delete and use GetSingleIncludingAsync instead.
    IQueryable<T> Find(long id);
    #endregion

    // eager loading
    Task<T> GetSingleIncludingAsync(
        long id, params Expression<Func<T, object>>[] includeProperties);

    Task<IEnumerable<T>> GetFiltered(
        Expression<Func<T, bool>> selector, FilteredSource filteredSource,
        Expression<Func<T, object>>[] includeProperties = null);

    Task<T> InsertAsync(T entity);
    Task<T> UpdateAsync(T entity);
    Task<T> DeleteAsync(T entity);

    #region Possible TODOs:
    //Task<IEnumerable<T>> FindBy(Expression<Func<T, bool>> predicate);
    //Task AddRange(IEnumerable<T> entities);
    //Task RemoveRange(IEnumerable<T> entities);
    #endregion

    Task SaveAsync();

这被注入到我的通用服务中:

public class GenericService<T> : IGenericService<T>
    where T : BaseEntity

    private IGenericRepository<T> _genericRepo;

    public GenericService(IGenericRepository<T> genericRepo)
    
        _genericRepo = genericRepo;
    

    public async Task<IEnumerable<T>> GetFiltered(
        Expression<Func<T, bool>> selector, FilteredSource filteredSource,
        Expression<Func<T, object>>[] includeProperties = null)
    
        return await _genericRepo.GetFiltered(selector, filteredSource,
            includeProperties);
    

    // eager loading
    public async Task<T> GetSingleIncludingAsync(long id, params Expression<Func<T, object>>[] includeProperties)
    
        IEnumerable<T> entities = await _genericRepo.GetFiltered(null, FilteredSource.GetAllIncluding, includeProperties);
        //return await Filter<long>(entities, x => x.Id, id).FirstOrDefaultAsync();
        return entities.SingleOrDefault(e => e.Id == id);
    

    public async Task<T> InsertAsync(T entity)
    
        var result = await _genericRepo.InsertAsync(entity);
        await _genericRepo.SaveAsync();
        return entity;
    

    public async Task<T> UpdateAsync(T entity)
    
        var result = await _genericRepo.UpdateAsync(entity);
        if (result != null)
        
            await _genericRepo.SaveAsync();
        
        return result;
    

    public async Task<T> DeleteAsync(T entity)
    
        throw new NotImplementedException();
    

服务的接口定义:

public interface IGenericService<T>
    where T : BaseEntity

    Task<IEnumerable<T>> GetFiltered(
        Expression<Func<T, bool>> selector, FilteredSource filteredSource,
        Expression<Func<T, object>>[] includeProperties = null);

    // eager loading
    Task<T> GetSingleIncludingAsync(long id, params Expression<Func<T, object>>[] includeProperties);

    Task<T> InsertAsync(T entity);
    Task<T> UpdateAsync(T entity);
    Task<T> DeleteAsync(T entity);

最后,这是控制器:

[Route("api/[controller]")]
public class EmployeesController : Controller

    private IGenericService<Employee> _genericService;

    public EmployeesController(IGenericService<Employee> genericService)
    
        _genericService = genericService;
    

    // GET: api/employees
    [HttpGet]
    public async Task<IEnumerable<Employee>> GetEmployeesAsync(
            string firstName = null, string lastName = null)
    
        return await _genericService.GetFiltered(
                e => (string.IsNullOrEmpty(firstName) || e.FirstName.Contains(firstName))
                && (string.IsNullOrEmpty(lastName) || e.LastName.Contains(lastName)),
                FilteredSource.GetAllIncluding,
                new Expression<Func<Employee, object>>[]  a => a.Organization,
                b => b.PayPlan,
                c => c.GradeRank,
                d => d.PositionTitle,
                e => e.Series,
                f => f.BargainingUnit 
            );
    

    // GET api/employees/5
    [HttpGet("id", Name = "GetEmployeeById")]
    public async Task<IActionResult> GetEmployeeByIdAsync(long id)
    
        //var employee = await _empRepo.Find(id).Include("Organization").Include("PayPlan").Include("GradeRank").Include("PositionTitle").Include("Series").Include("BargainingUnit").SingleAsync();
        var employee = await _genericService.GetSingleIncludingAsync(id,
            a => a.Organization,
            b => b.PayPlan,
            c => c.GradeRank,
            d => d.PositionTitle,
            e => e.Series,
            f => f.BargainingUnit);

        if (employee == null)
        
            return NotFound();
        
        else
        
            return new ObjectResult(employee);
        
    

    // PUT api/employees/id
    [HttpPut("id")]
    public async Task<IActionResult> PutEmployeeAsync([FromBody] Employee emp)
    
        var employee = await _genericService.UpdateAsync(emp);
        if (employee == null)
        
            return NotFound();
        

        return new ObjectResult(employee);
    

我只是不确定如何插入中间服务层。

【问题讨论】:

【参考方案1】:

根据大卫的回答,我不得不在我的服务实现类中删除“抽象”。不过,我在课堂上也有一些抽象方法和属性。因此,在将它们设为非抽象并创建 公共构造函数之后,我就能够注册服务了。

【讨论】:

【参考方案2】:

根据 Bartosz 的回答,出现此消息的另一个原因是,如果您尝试使用像这样的通用具体类型来满足非通用接口:

services.AddScoped(typeof(IMyDependency), typeof(MyDependency&lt;,&gt;));

这不起作用,因为 DI 容器不知道在实例化 MyDependency 时要提供什么通用参数。要么接口必须转换为泛型,要么你需要一个工厂来手动实例化它。

【讨论】:

【参考方案3】:

到目前为止,很好的问题和很好的答案......

如果你的问题不同但错误信息相同

...您正在为默认实现注册服务,未指定实现类型,如下所示:

services.AddScoped<IMyDependency>();

那么这个错误是没有用的,因为它没有详细说明为什么事情不起作用:

无法为服务类型“MyApp.IMyDependency”实例化实现类型“MyApp.IMyDependency”。

在这种情况下,将服务注册更改为:

services.AddScoped<IMyDependency, MyDependency>();

这将改善错误消息,并告诉您问题出在哪里,如下所示:

无法构造某些服务(验证服务描述符“ServiceType: MyApp.IMyDependency Lifetime: Transient ImplementationType: MyApp.MyDependency”时出错:无法解析“MyApp.ILowerDependency”类型的服务 在尝试激活“MyApp.IMyDependency”时。)

在默认的 ASP.NET 核心 DI 容器中,需要显式注册整个依赖关系图(可能除了 ILogger 等一些异常

【讨论】:

【参考方案4】:

这件事最近发生在我身上。我将实现类标记为“抽象”,这是早期设计的产物。我删除了它,容器能够毫无问题地实例化该类。

【讨论】:

【参考方案5】:

service 类没有从 IService 继承时发生在我身上 界面

【讨论】:

【参考方案6】:

我是个白痴。 我有实现的接口。 我改变了:

services.AddScoped(typeof(IGenericService<>), typeof(IGenericService<>));

services.AddScoped(typeof(IGenericService<>), typeof(GenericService<>));

【讨论】:

同样的错误。我正在使用别名并认为导致错误,例如using shortName= Foo.Repository.Repositories.Contacts; 这其实很好,问题是混淆了接口/实现顺序。 我添加了一个抽象实现类。这个错误怎么这么流行

以上是关于为啥我的通用服务出现“无法实例化实现类型”错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 SQL 查询会出现内部服务器错误?

为啥我的 Java appengine 应用程序在 5 年后没有任何问题出现“500 服务器错误”?

为啥我将网站放在 debian 服务器上时出现 cayenne 连接错误

为啥我的 MySql 出现用户注册错误

为啥我的navicat for mysql 一按就出现错误 还有我为啥创不到数据库 求大神解答!

我的电脑下载某些网站的东西,为啥老是出现404错误的报告