In my ASP.NER Core Web API Project, I have this code:
public interface IUriPaginationService
{
public Uri GetPaginationUri(int page, string actionUrl);
}
public class UriPaginationService : IUriPaginationService
{
private readonly string _baseUri;
public UriPaginationService(string baseUri)
{
_baseUri = baseUri;
}
public Uri GetPaginationUri(int page, string actionUrl)
{
string baseUrl = $"{_baseUri}{actionUrl}";
return new Uri(baseUrl);
}
}
public abstract class AuditableBaseEntity
{
public AuditableBaseEntity()
{
CreatedDate = DateTime.Now;
}
[Key]
public virtual long Id { get; set; }
[JsonIgnore]
public bool IsDeleted { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CreatedDate { get; set; }
public long? LastUpdatedBy { get; set; }
}
Repositories:
public interface IBaseRepository<T> where T : AuditableBaseEntity
{
Task<IEnumerable<T>> GetAll();
Task<T> GetById(long id);
bool EntityExists(long id);
}
public class BaseRepository<T> : IBaseRepository<T> where T : AuditableBaseEntity
{
private readonly DDMDbContext _context;
private DbSet<T> _entities;
public BaseRepository(DDMDbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAll()
{
var list = await _entities.Where(x => x.IsDeleted == false).ToListAsync();
return list;
}
public async Task<T> GetById(long id)
{
return await _entities.FindAsync(id);
}
public bool EntityExists(long id)
{
return _entities.Any(x => x.Id == id && x.IsDeleted == false);
}
}
UnitOfWork:
public interface IUnitOfWork : IDisposable
{
IBaseRepository<Merchant> MerchantRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
private readonly DDMDbContext _context;
public UnitOfWork(DDMDbContext context)
{
_context = context;
}
private readonly IBaseRepository<Merchant> _merchantRepository;
public IBaseRepository<Merchant> MerchantRepository => _merchantRepository ?? new BaseRepository<Merchant>(_context);
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
}
}
Services:
public interface IMerchantService
{
public Task<IEnumerable<Merchant>> GetMerchants();
public bool EntityExists(long id);
public Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage);
}
public class MerchantService : IMerchantService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IUriPaginationService _uriPaginationService;
private readonly DDMDbContext _context;
public MerchantService(IUnitOfWork unitOfWork, IUriPaginationService uriPaginationService, DDMDbContext context)
{
_unitOfWork = unitOfWork;
_uriPaginationService = uriPaginationService;
_context = context;
}
public async Task<IEnumerable<Merchant>> GetMerchants()
{
return await _unitOfWork.MerchantRepository.GetAll();
}
public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
{
string nextRoute = null, previousRoute = null;
IEnumerable<Merchant> data = await _unitOfWork.MerchantRepository.GetAll();
var mapper = new EntityMapper();
var merchantsDto = data.Select(m => mapper.FromMerchantToMerchantGetDto(m)).ToList();
GenericPagination<MerchantGetDto> objGenericPagination = GenericPagination<MerchantGetDto>.Create(merchantsDto, page, sizeByPage);
ResponsePagination<GenericPagination<MerchantGetDto>> response = new ResponsePagination<GenericPagination<MerchantGetDto>>(objGenericPagination);
response.CurrentPage = objGenericPagination.CurrentPage;
response.HasNextPage = objGenericPagination.HasNextPage;
response.HasPreviousPage = objGenericPagination.HasPreviousPage;
response.PageSize = objGenericPagination.PageSize;
response.TotalPages = objGenericPagination.TotalPages;
response.TotalRecords = objGenericPagination.TotalRecords;
response.Data = objGenericPagination;
if (response.HasNextPage)
{
nextRoute = $"/merchants?page={(page 1)}";
response.NextPageUrl = _uriPaginationService.GetPaginationUri(page, nextRoute).ToString();
}
else
{
response.NextPageUrl = null;
}
if (response.HasPreviousPage)
{
previousRoute = $"/merchants?page={(page - 1)}";
response.PreviousPageUrl = _uriPaginationService.GetPaginationUri(page, previousRoute).ToString();
}
else
{
response.PreviousPageUrl = null;
}
return response;
}
public bool EntityExists(long id)
{
return _unitOfWork.MerchantRepository.EntityExists(id);
}
public async Task<Merchant> GetById(long id)
{
return await _unitOfWork.MerchantRepository.GetById(id);
}
}
Controller:
[Produces("application/json")]
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AdminController : ControllerBase
{
private readonly IMerchantService _merchantService;
public AdminController(MerchantService merchantService)
{
_merchantService = merchantService;
}
[HttpGet("merchants")]
public async Task<ResponsePagination<GenericPagination<MerchantGetDto>>> GetAll(int page, int sizeByPage)
{
return await _merchantService.GetAll(page, sizeByPage);
}
}
startup:
public void ConfigureServices(IServiceCollection services)
{
// services.AddMvc();
services.AddControllers();
services.AddDb(Configuration);
services.AddJwtAuthentication(Configuration);
services.AddMvcCoreFramework(Configuration);
services.AddAppAuthorization(Configuration);
services.AddControllersWithViews();
services.AddRazorPages();
services.AddVersioning();
services.AddSwagger();
services.AddRouting(options => options.LowercaseUrls = true);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IUriPaginationService>(provider =>
{
var accesor = provider.GetRequiredService<IHttpContextAccessor>();
var request = accesor.HttpContext.Request;
var absoluteUri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent());
return new UriPaginationService(absoluteUri);
});
services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddTransient<IMerchantService, MerchantService>();
}
When I use this on postman get request:
https://localhost:44341/api/v1/merchant/mandates
I got this error:
System.InvalidOperationException: Unable to resolve service for type 'API.Infrastructure.Services.Concrete.MerchantService' while attempting to activate 'API.Web.Controllers.v1.MerchantController'. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
How do I resolve this:
Thanks
CodePudding user response:
The controller is dependent on the implementation (class)
public AdminController(MerchantService merchantService)
{
_merchantService = merchantService;
}
while you registered the abstraction (interface).
services.AddTransient<IMerchantService, MerchantService>();
Based on the registration it is most likely the controller was meant to be dependent on the interface (abstraction)
public AdminController(IMerchantService merchantService) //<-- CHANGED TO INTERFACE
{
_merchantService = merchantService;
}
Updating the controller constructor to be dependent on the registered abstraction will fix the shown exception.