lolol
lolol

Reputation: 4390

Repository pattern dependency injection using Dapper

My Startup.cs contains 40 repositories:

services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IXRepository, XRepository>();
... 40 more lines ...

I'm trying to find a way to have this mess in a single line, but I'm failing miserably to put my head around this, I have several methods that are not available in the interface. Can someone provide some help? I understand why it is not working, it does not have a concrete repository, but I'm no closer to making this work.

InvalidOperationException: Unable to resolve service for type...

// IRepository.cs
public interface IRepository
{
}

// IUserRepository.cs
public interface IUserRepository : IRepository
{
    User ReadToken(string email, string password);
}

// BaseRepository.cs
public class BaseRepository : IDisposable
{
    protected IDbConnection PostgreSQL;

    public BaseRepository(IDbConnection postgreSQL)
    {
        PostgreSQL = postgreSQL;
    }

    public void Dispose()
    {
    }
}

// UserRepository.cs
public class UserRepository : BaseRepository, IUserRepository
{
    public UserRepository(IDbConnection postgreSQL) : base(postgreSQL)
    {
    }

    public User ReadToken(string email, string password)
    {
        object parameters;
        string sql;

        parameters = new
        {
            email,
            password
        };

        sql =
        @"
        SELECT
            user_id AS id,
            token
        FROM users
        WHERE
            email = @email AND
            password = CRYPT(@password, password) AND
            active = TRUE;
        ";

        var user = base.PostgreSQL.Query<User>(sql, parameters).SingleOrDefault();

        if (user == null)
            throw new UnauthorizedException("User", "User not found.");

        return user;
    }
}

// UsersController.cs
public class UsersController : ControllerBase
{
    protected IUserRepository UserRepository;

    public UsersController(IUserRepository userRepository)
    {
        UserRepository = userRepository;
    }
}

// Startup.cs
services.AddTransient<IRepository, BaseRepository>();

Upvotes: 2

Views: 2289

Answers (2)

Nick Chapsas
Nick Chapsas

Reputation: 7200

You can do that with Scrutor

It offers assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection

All those repositories can be summed up to something like this:

services.Scan(x => x.FromAssemblyOf<IAnAssemblyRegistrationMarker>()
        .AddClasses(filter => filter.AssignableTo(typeof(IRepository)))
        .AsImplementedInterfaces()
        .WithScopedLifetime());

IAnAssemblyRegistrationMarker is an empty interface to point at the assembly (project) you want to scan

AddClasses Adds all public, non-abstract classes from the selected assemblies that matches the requirements specified in the

AsImplementedInterfaces Registers each matching concrete type as all of its implemented interfaces

WithScopedLifetime Registers each matching concrete type with Scoped Lifetime (You also have WithSingletonLifetime and WithTransientLifetime)

The only requirement in the code example above is that the repositories implement IRepository in order for you to target only the necessary items.

Disclaimer: I am not associated with Scrutor in any way. I just like the thing.

Upvotes: 3

Alexey Andrushkevich
Alexey Andrushkevich

Reputation: 6162

What you are looking for is called convention based registration. This gives you ability register all types which for example ends with Repository as the interfaces they implement. However the built-in ASP.NET Core IOC is very lightweight and doesn't provide such functionality. So you can either wrap it up with your code which scans all referenced assemblies, look for types by a pattern and then add them to ServiceCollection or you can use different IOC implementation that provides this functionality and supports .Net Core e.g. Autofac, StructureMap etc.

Upvotes: 3

Related Questions