我该如何解决 "Unable to resolve service for type '' while attempting to activate ''"

How do I resolve "Unable to resolve service for type '' while attempting to activate ''"

当我尝试从 Postman 请求 .net core 3.1 WebAPI 时出现错误

System.InvalidOperationException: Unable to resolve service for type 'PaymentsAPI.Repository.PaymentService' while attempting to activate 'PaymentsAPI.Controllers.PaymentController' '

Startup.cs

public void ConfigureServices(IServiceCollection services)
{      
    services.AddControllers();
  
    services.AddCors(c =>
    {
        c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
    });
    services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(Configuration.GetConnectionString("SqlSvrConn")));
    services.AddTransient<IAsyncPaymentsService<PaymentDetail>, PaymentService>();
}

IAsyncPaymentsService.cs

public interface IAsyncPaymentsService<TEntity>
{        
    Task<IEnumerable<TEntity>> GetAllAsync();
}

PaymentService.cs

public class PaymentService : IAsyncPaymentsService<PaymentDetail>
{
    private readonly ApplicationDbContext _dbContext;
    

    public async Task<IEnumerable<PaymentDetail>> GetAllAsync()
    {
        return await _dbContext.PaymentDetails.ToListAsync();
    }
}

PaymentController.cs

[ApiController]
[Route("[controller]")]
public class PaymentController : ControllerBase
{
    private readonly ApplicationDbContext _context;
    private readonly PaymentService _service;
    public PaymentController(ApplicationDbContext context, PaymentService service)
    {
        _context = context;
        _service = service;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<PaymentDetail>>> GetAsync()
    {
        var items = (await _service.GetAllAsync());
        return Ok(items);
    }
}

我已经尝试重新排列容器中的服务顺序,但错误仍然存​​在。我错过了什么?

快速解决方法是将控制器构造函数更改为依赖于抽象而不是实现,因为抽象是在容器中注册的内容。

//...

private readonly ApplicationDbContext _context;
private readonly IAsyncPaymentsService<PaymentDetail> _service;

public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{
    _context = context;
    _service = service;
}

//...

但是,如果需要,泛型抽象可以派生为封闭类型

public interface IPaymentService :  IAsyncPaymentsService<PaymentDetail> {

}

应用于实施

public class PaymentService : IPaymentService {
    //...omitted for brevity
}

注册容器

services.AddTransient<IPaymentService, PaymentService>();

并在控制器中重构

//...

private readonly ApplicationDbContext _context;
private readonly IPaymentService _service;

public PaymentController(ApplicationDbContext context, IPaymentService service)
{
    _context = context;
    _service = service;
}

//...

要使此工作正常进行,您唯一需要更改的是在控制器中接受接口而不是具体服务。

public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{...}

出于测试等各种原因,建议采用具体类型。如果您确实需要具体类型,则必须改为将注册更改为

services.AddTransient<PaymentService>();

并保持控制器的构造函数不变。