Reputation: 1009
When I attempt requests to a .net core 3.1 WebAPI from Postman I am getting error
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);
}
}
I have tried rearranging the order of services in the container but the error still persists. What am I missing ?
Upvotes: 7
Views: 40669
Reputation: 21699
The only thing you should have to change to make this work is to accept the interface into your controller instead of the concrete service.
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{...}
This is recommended over taking the concrete type for various reasons such as testing. If you truly need the concrete type, you'd have to instead change your registration to
services.AddTransient<PaymentService>();
and leave your controller's constructor as is.
Upvotes: 1
Reputation: 246998
The quick fix would be to change the controller constructor to depend on the abstraction instead of the implementation since the abstraction is what was registered with the container.
//...
private readonly ApplicationDbContext _context;
private readonly IAsyncPaymentsService<PaymentDetail> _service;
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{
_context = context;
_service = service;
}
//...
However, the generic abstraction could derived to a closed type if so desired
public interface IPaymentService : IAsyncPaymentsService<PaymentDetail> {
}
applied to the implementation
public class PaymentService : IPaymentService {
//...omitted for brevity
}
registered with the container
services.AddTransient<IPaymentService, PaymentService>();
and refactored in the controller
//...
private readonly ApplicationDbContext _context;
private readonly IPaymentService _service;
public PaymentController(ApplicationDbContext context, IPaymentService service)
{
_context = context;
_service = service;
}
//...
Upvotes: 7