'There is no argument given that corresponds to the required formal parameter 'dbContext' of 'GenericRepositoryAsync<Employee>'

I am implementing Clean Architecture design pattern using asp.net core 6 and Visual Studio 2022. In this case I am trying to use both EntityFramework Core (6.0.3) and Dapper (2.0.123) ORMs in accessing and doing other Create,Update, Delete operations. Here I am trying to leverage Dapper for readonly operations and EntityFramework Core for Create, Update, Delete opertaions

Following are the parts of the solution:

  1. Core

1.1 Domain - This is a class library with target framework .net 6.0. All the Entities and the most common models are available here.

1.2 Application: This is a class library with target framework .net 6.0. It contains Interfaces, CQRS Features, Exceptions, Behaviors related code components.

  1. Infrastructure

2.1 Infrastructure.Identity : This is a class library with target framework .net 6.0. It contains all the code related to Identity implementation.

2.2 Infrastructure.Persistence : This is a class library with target framework .net 6.0. It contains all the code related to data access which includes both EntityFramework and Dapper.

2.3 Infrastructure.Shared: This is a class library with target framework .net 6.0. It contains all the code that is common to the other Infrastructure Layers and has the possibility of use in nearly all the Infrastructure Layers.

  1. WebApi: This project is using asp.net core 6.0 web api template

Code :

Core->Domain->Entities:

public class Product : AuditableBaseEntity
{
    public string Name { get; set; }

    public string Barcode { get; set; }

    public string Description { get; set; }

    public decimal Rate { get; set; }
}

Core->Application>Contracts:

public interface IApplicationDbContext
{
    public IDbConnection Connection { get; }

    DatabaseFacade Database { get; }

    public DbSet<Product> Product { get; }

    Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}

public interface IApplicationReadDbConnection
{
    Task<IReadOnlyList<T>> QueryAsync<T>(string sql, object? param, IDbTransaction? transaction = null, CancellationToken cancellationToken = default);
    Task<T> QueryFirstOrDefaultAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default);
    Task<T> QuerySingleAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default);
}

public interface IApplicationWriteDbConnection : IApplicationReadDbConnection
{
    Task<int> ExecuteAsync(string sql, object? param, IDbTransaction? transaction = null, CancellationToken cancellationToken = default);
}

public interface IGenericRepositoryAsync<T>
    where T : class
{
    Task<T> Get(int id);
    Task<IReadOnlyList<T>> GetAll();
    Task Add(T entity);
    Task<bool> Exists(int id);
    void Update(T entity);
    void Delete(T entity);
}

public interface IUnitOfWork : IDisposable
{
    IProductRepository ProductRepository { get; }

    Task<bool> SaveAsync();
}

public interface IProductRepositoryAsync : IGenericRepositoryAsync<Product>
{
    Task<bool> IsUniqueBarcodeAsync(string barcode);
}

Infrastructure->Persistence->Contexts:

public partial class ApplicationDbContext : DbContext, IApplicationDbContext
{
    public ApplicationDbContext()
    {
    }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    public virtual DbSet<Product> Product => Set<Product>();
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
        }
    }

    public IDbConnection Connection => Database.GetDbConnection();
}

Infrastructure->Persistence->Connections:

public class ApplicationReadDbConnection : IApplicationReadDbConnection, IDisposable
{
    private readonly IDbConnection connection;
    public ApplicationReadDbConnection(IConfiguration configuration)
    {
        connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection"));
    }

    public async Task<IReadOnlyList<T>> QueryAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return (await connection.QueryAsync<T>(sql, param, transaction)).AsList();
    }

    public async Task<T> QueryFirstOrDefaultAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return await connection.QueryFirstOrDefaultAsync<T>(sql, param, transaction);
    }

    public async Task<T> QuerySingleAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return await connection.QuerySingleAsync<T>(sql, param, transaction);
    }

    public void Dispose()
    {
        connection.Dispose();
    }
}

public class ApplicationWriteDbConnection : IApplicationWriteDbConnection
{
    private readonly IApplicationDbContext context;
    public ApplicationWriteDbConnection(IApplicationDbContext context)
    {
        this.context = context;
    }

    public async Task<int> ExecuteAsync(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return await context.Connection.ExecuteAsync(sql, param, transaction);
    }

    public async Task<IReadOnlyList<T>> QueryAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return (await context.Connection.QueryAsync<T>(sql, param, transaction)).AsList();
    }

    public async Task<T> QueryFirstOrDefaultAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return await context.Connection.QueryFirstOrDefaultAsync<T>(sql, param, transaction);
    }

    public async Task<T> QuerySingleAsync<T>(string sql, object? param = null, IDbTransaction? transaction = null, CancellationToken cancellationToken = default)
    {
        return await context.Connection.QuerySingleAsync<T>(sql, param, transaction);
    }
}

Infrastructure->Persistence->Repositories:

public class GenericRepositoryAsync<T> : IGenericRepositoryAsync<T> where T : class
{
    private readonly ApplicationDbContext _dbContext;
    public GenericRepositoryAsync(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task Add(T entity)
    {
        await _dbContext.Set<T>().AddAsync(entity);
    }

    public async Task<bool> Exists(int id)
    {
        var entity = await Get(id);
        return entity != null;
    }

    public async Task<T> Get(int id)
    {
        return await _dbContext.Set<T>().FindAsync(id);
    }

    public async Task<IReadOnlyList<T>> GetAll()
    {
        return await _dbContext.Set<T>().ToListAsync();
    }

    public void Delete(T entity)
    {
        _dbContext.Set<T>().Remove(entity);
    }

    public void Update(T entity)
    {
        _dbContext.Set<T>().Update(entity);
    }
}

public class UnitOfWork : IUnitOfWork
{
    private IProductRepository? _productRepository;
    private readonly ApplicationDbContext _dbContext;
    
    public UnitOfWork(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
    }

    
    public IProductRepository ProductRepository => _productRepository ??= new ProductRepository(_dbContext);
    public void Dispose()
    {
        _dbContext.Dispose();
        GC.SuppressFinalize(this);
    }

    public async Task<bool> SaveAsync()
    {
        return await _dbContext.SaveChangesAsync() > 0;
    }
}

public class ProductRepository : GenericRepositoryAsync<Product>, IProductRepository
{
    public IApplicationDbContext _dbContext { get; }

    public IApplicationReadDbConnection _readDbConnection { get; }

    public IApplicationWriteDbConnection _writeDbConnection { get; }

    public ProductRepository(IApplicationDbContext dbContext, IApplicationReadDbConnection readDbConnection, IApplicationWriteDbConnection writeDbConnection)
    {
        _dbContext = dbContext;
        _readDbConnection = readDbConnection;
        _writeDbConnection = writeDbConnection;
    }

    public Task<bool> IsUniqueBarcodeAsync(string barcode)
    {
        return await _dbContext.Products.AllAsync(p => p.Barcode != barcode);
    }
}

An error is displayed in context to the constructor of the ProductRepository.cs

There is no argument given that corresponds to the required formal parameter 'dbContext' of 'GenericRepositoryAsync<Employee>.GenericRepositoryAsync(ApplicationDbContext)'

one more error in resolving the dbContext in the UnitOfWork.cs

cannot convert from 'Persistence.Contexts.ApplicationDbContext' to 'Application.Contracts.Persistence.IApplicationReadDbConnection'

I have been referring to the below mentioned articles in creating this application:

http://codewithmukesh.com/project/aspnet-core-webapi-clean-architecture%E2%80%8B/

https://codewithmukesh.com/blog/using-entity-framework-core-and-dapper/

Can anyone help me with their guidance to fix this issue?



Solution 1:[1]

One of your issues is that you need to call the constructor of the base class in your ProductRepository constructor:

Refactor this:

public ProductRepository(IApplicationDbContext dbContext, IApplicationReadDbConnection readDbConnection, IApplicationWriteDbConnection writeDbConnection) 
{
    _dbContext = dbContext;
    _readDbConnection = readDbConnection;
    _writeDbConnection = writeDbConnection;
}

to this:

public ProductRepository(IApplicationDbContext dbContext, IApplicationReadDbConnection readDbConnection, IApplicationWriteDbConnection writeDbConnection) : base(dbContext)
{
    _readDbConnection = readDbConnection;
    _writeDbConnection = writeDbConnection;
}

Also make the Generic class DbContext protected or public and remove it from the inheriting classes.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SBFrancies