I’m working on a component, let’s call it MyComponent
, which is intended to be used by various applications. These applications will get MyComponent
as a NuGet package for instance.
Assume that MyComponent
is a business logic for user management with the following public API:
namespace MyComponent.API.Users.Queries.GetUser;
public record UserModel(string Name, string Email);
public interface IGetUsersQuery
{
IReadOnlyList<UserModel> Execute();
}
namespace MyComponent.API.Services.Database;
public record UserData(int Id, string Name, string Email, string PasswordHash);
public interface IDatabaseService
{
IList<UserData> Users { get; set; }
void Save();
}
The IGetUsersQuery
interface is part of the business logic, so it is implemented internally by MyComponent
:
namespace MyComponent.Users.Queries.GetUser;
internal class GetUsersQuery(IDatabaseService database) : IGetUsersQuery
{
public IReadOnlyList<UserModel> Execute()
{
return database.Users.Select(ToUserModel).ToList();
}
private static UserModel ToUserModel(UserData userData)
{
return new UserModel(userData.Name, userData.Email);
}
}
MyComponent
requires the application using it, let’s call it SomeApplication
, to implement the IDatabaseService
:
namespace SomeApplication.Persistence;
internal class DatabaseService : IDatabaseService
{
public IList<UserData> Users { get; set; } = new List<UserData>();
public void Save()
{
Console.WriteLine("All changes are saved");
}
}
SomeApplication
can query users by implementing some kind of controller that depends on the IGetUsersQuery
interface:
namespace SomeApplication.Presentation.Users;
internal class UsersController(IGetUsersQuery query)
{
public void ShowUsers()
{
foreach(var user in query.Execute())
{
Console.WriteLine(user);
}
}
}
It is clear that MyComponent
depends on an interface that SomeApplication
implements, and vice versa.
Assume that SomeApplication
uses the Microsoft.Extensions.DependencyInjection
to resolve dependencies. If the implementations in MyComponent
were public, then SomeApplication
would have an easy job:
private static ServiceProvider CreateServices()
{
var serviceProvider = new ServiceCollection()
.AddSingleton<IGetUsersQuery, GetUsersQuery>()
.AddSingleton<IDatabaseService, DatabaseService>()
.AddSingleton<UsersController>()
.BuildServiceProvider();
return serviceProvider;
}
- How can I make
SomeApplication
resolve dependencies on interfaces inMyComponent
if the implementations are internal? - How can
MyComponent
be independent of the dependency injection solution used bySomeApplication
, if any?
I also thought about using reflection, but I would avoid this approach, because it would make SomeApplication
depend on implementation details of MyComponent
.