Using Both

To use both you have to combine two methods. First create the IMyRepository Interface to implement additional methods:

public interface IMyRepository<TEntity> : IRENRepository<TEntity> where TEntity : class
{
    Task MyCustomFunction(CancellationToken cancellationToken = default);
}

Then create MyRepository class that inherits from RENRepository and IMyRepository and contains overriden method(s):

public class MyRepository<TEntity> : RENRepository<TEntity>, IMyRepository<TEntity> where TEntity : class
{
    public MyRepository(RENDbContext context) : base(context) { }

    public override Task<TEntity?> GetSingleAsync(Expression<Func<TEntity, bool>> filter,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null,
        bool isReadOnly = false,
        CancellationToken cancellationToken = default)
    {
        Console.WriteLine("Getting custom async......");
        // Other custom implementations
        return base.GetSingleAsync(filter, null, include, isReadOnly, cancellationToken);
    }

    public Task MyCustomFunction(CancellationToken cancellationToken = default)
    {
        return Task.Factory.StartNew(() =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            Console.WriteLine("This is my custom Function");
            // other custom implementations!

        }, cancellationToken);
    }
}

To use MyRepository class with the interface, we created IMyRepository interface. We need to add a repository getter function to get repositories in IMyRepository type instead of IRENRepository. We need that because IRENRepository does not contain our custom function!

public interface IMyUnitOfWork<TDbContext>: IRENUnitOfWork<TDbContext> where TDbContext : RENDbContext
{
    IMyRepository<TEntity>? GetMyRepository<TEntity>() where TEntity : class;
}
public class MyUnitOfWork<TDbContext> : RENUnitOfWork<TDbContext>, IMyUnitOfWork<TDbContext> where TDbContext : RENDbContext
{
    public MyUnitOfWork(TDbContext context) : base(context) { }

    public IMyRepository<TEntity>? GetMyRepository<TEntity>() where TEntity: class
    {
        return (IMyRepository<TEntity>?)Activator.CreateInstance(typeof(MyRepository<TEntity>), new object[] { _context });
    }
}

In Program.cs we need to register MyUnitOfWork class from interface IMyUnitOfWork since it contains the repository getter method.

builder.Services.AddScoped(typeof(IMyUnitOfWork<>), typeof(MyUnitOfWork<>));

Then you can use your final Repository and Unit Of Work classes like this:

public class HomeController : ControllerBase
{
    private readonly IMyRepository<User> _customUserRepository;
    private readonly ICacheService _cacheService;

    public HomeController(IMyUnitOfWork<RENDbContext> uow)
    {
        _customUserRepository = uow.GetMyRepository<User>();
    }

    [HttpGet, Route("Index")]
    public async Task<IActionResult> Index()
    {
        await _customUserRepository.MyCustomFunction(); // our custom function
        await _customUserRepository.GetSingleAsync(_ => _.Id == 1); // our overriden function
        return Ok();
    }
}

Last updated