Make internal great again!
Ever been annoyed that your application's entry point, Program.cs, must
know about the whole dependency graph of every project in your solution to
be able to configure the DI container?
Ever been annoyed that you can't mark a class or interface as internal because
it makes them difficult to use via Dependency Injection?
AddLib can help you 🎉
AddLib provides a simple convention for encapsulating the internal types and functionality of class libraries.
dotnet add package AddLibAddLib has a two external references to the lightweight
Microsoft.Extensions.DependencyInjection.Abstractions and
Microsoft.Extensions.Configuration.Abstractions packages, which will
also be installed implicitly.
In your class library project, add a class that implements AddLib.ILibrary:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MySolution.Domain;
public class Library : AddLib.ILibrary
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString("Default");
services.AddTransient<IDatabaseContext>(x => new DatabaseContext(connectionString));
services.AddTransient<IInternalDomainUtility, InternalDomainUtility>();
services.AddTransient<IUserDomainService, UserDomainService>();
}
}In your application entry point, e.g. Program.cs, register the Library
by pointing to the type:
services.AddLibrary<MySolution.Domain.Library>(configuration);Or let AddLib scan assemblies for the ILibrary implementations:
// Scans the given assembly
services.AddLibrary(typeof(MySolution.Domain.IUserDomainService).Assembly, configuration);You might ask: "Don't I still need to make all the classes and interfaces
public so I can reference them in test projects?"
Not necessarily. You can use the InternalsVisibleTo attribute.
Either in your Project.csproj or Directory.Build.props:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>MySolution.UnitTests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>Or as code, placed anywhere in your library project:
[assembly: InternalsVisibleTo("MySolution.UnitTests")]