DI excpetion for service in api with Data Access Layer

67 views Asked by At

I'm trying to use DI and Access Layer Pattern copying this https://davek.dev/crud-with-mongodb-in-c-and-net-6#heading-service-layer. So my project structure is like this:

Project Structure

where DbAccess Has This Interface and Implementation:

public class MongoDataAccess : IMongoDataAccess
{
    private readonly IMongoClient _client;

    public MongoDataAccess(string connectionString)
    {
        var settings = MongoClientSettings.FromConnectionString(connectionString);
        _client = new MongoClient(settings);
    }

    public IMongoCollection<T> GetCollection<T>(string databaseName, string collectionName)
    {
        return _client.GetDatabase(databaseName).GetCollection<T>(collectionName);
    }
}

When in Data I have Interface/Class pairs for all the collections with CRUD operations in it, for example:

public class CyborgData : ICyborgData
{
    private readonly IMongoCollection<Cyborg> _cyborgs;

    public CyborgData(IMongoDataAccess mongoDataAccess)
    {
        _cyborgs = mongoDataAccess.GetCollection<Cyborg>("cyborgstore", "cyborgs");
    }

    public async Task CreateCyborgAsync(Cyborg cyborg) => await _cyborgs.InsertOneAsync(cyborg);

    public async Task<Cyborg> GetCyborgAsync(string id)
    {
        var results = await _cyborgs.FindAsync(c => c.Id == id);
        return await results.SingleAsync();
    }
    
    public async Task<IList<Cyborg>> GetAllCyborgAsync()
        => await _cyborgs.AsQueryable().ToListAsync();

    public async Task UpdateCyborgAsync(Cyborg cyborg)
        => await _cyborgs.FindOneAndReplaceAsync(c => c.Id == cyborg.Id, cyborg);

    public async Task DeleteCyborgAsync(string id)
        => await _cyborgs.DeleteOneAsync(c => c.Id == id);
}

And then back to the API I have service interface/implementation to add in build:

public class CyborgService : ICyborgService
    {
        private readonly ICyborgData _cyborgData;

        public CyborgService(ICyborgData cyborgData)
        {
            _cyborgData = cyborgData;
        }

        public async Task CreateCyborgAsync(Cyborg cyborg)
        {
            await _cyborgData.CreateCyborgAsync(cyborg);
        }

        public async Task<Cyborg> GetCyborgAsync(string id)
            => await _cyborgData.GetCyborgAsync(id);

        public async Task<IList<Cyborg>> GetAllCyborgAsync()
            => await _cyborgData.GetAllCyborgAsync();

        public async Task UpdateCyborgAsync(Cyborg cyborg)
            => await _cyborgData.UpdateCyborgAsync(cyborg);

        public async Task DeleteCyborgAsync(string id)
            => await _cyborgData.DeleteCyborgAsync(id);
    }

Which I add in Programm.cs with my ConnectionAccess: builder.Services.AddSingleton<IMongoDataAccess>(new MongoDataAccess("connection string"); builder.Services.AddTransient<ICyborgService, CyborgService>();

But instead of working app gives me this long exception:

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CyborgStoreApi.Services.ICyborgService Lifetime: Transient ImplementationType: CyborgStoreApi.Services.CyborgService': Unable to resolve service for type 'DataAccess.Data.ICyborgData' while attempting to activate 'CyborgStoreApi.Services.CyborgService'.)'

InvalidOperationException: Error while validating the service descriptor 'ServiceType: CyborgStoreApi.Services.ICyborgService Lifetime: Transient ImplementationType: CyborgStoreApi.Services.CyborgService': Unable to resolve service for type 'DataAccess.Data.ICyborgData' while attempting to activate 'CyborgStoreApi.Services.CyborgService'.

InvalidOperationException: Unable to resolve service for type 'DataAccess.Data.ICyborgData' while attempting to activate 'CyborgStoreApi.Services.CyborgService'.

In debugger I see that for some reason my MongoDataAcess doesn't has any implementation:

Lifetime = Singleton, ServiceType = {Name = "IMongoDataAccess" FullName = "DataAccess.DbAccess.IMongoDataAccess"}, ImplementationType = null

while my CyborgService has.

1

There are 1 answers

0
Dorialean On

Thanks to @Steven. I understood that I need to configurate all the AccessLayer (Data folder in my case) accessingServices in my api before I can use my buisness logic layer in apiService(CyborgService in my case) like this:

builder.Services.AddScoped<ICyborgData, CyborgData>();

Thank you!