generate extension-method for registering generated classes with `Microsoft.Extensions.DependencyInjection`
The source-generator should emit an extension-method for use with IServiceCollection, which registers all types being generated, to reduce the amount of boilerplate-code necessary in order to utilize injection of typealized resources.
think about the following project structure, where all projects have TypealizR consumed:
- Solution
Library ALibrary B- references
Microsoft.Extensions.DependencyInjection.Abstractions
- references
Library C- references
Library B
- references
Library DLibrary E- references
Library D - references
Microsoft.Extensions.DependencyInjection.Abstractions
- references
- App
- references
Library A - references
Library B - references
Library C -
does not reference
Library D - references
Library E - references
Microsoft.AspNetCore- references
Microsoft.Extensions.Logging- references
Microsoft.Extensions.DependencyInjection.Abstractions
- references
- references
- references
The generated method(s) would need to register all generated types from
Library ALibrary BLibrary CLibrary DLibrary E
Ideally in a way, that does not need knowledge within App of which libraries are actually referenced. At least within user-code.
Ideally2: without the need to reflect on said references, though...falling back to reflection actually defeats the whole purpose of source generation.
Problem here: source-generators cannot be stacked upon each other:
https://stackoverflow.com/a/68506422/4136104
However, it looks like assembly references affect the order of invocations within a solution.
That said, the expected order of invocations would be:
Library ALibrary BLibrary CLibrary DLibrary EApp<--this is the assembly that´d actually call the extension-method
If that´s true, we could choose to scan all direct and indirect references of Appfor types emitted by the source-generator and generate an extension-method which registers the relevant types with IServiceCollection
Just wondering how we could determine when to actually emit such an extension-method - which assembly sits "on top" enough to actually benefit from such method and needs to actually register dependencies?
Is it OK to jsut emit variants on all projects? Then theses would need to exist on seperate namespaces, though...
Oh, and it should not degrade build-times in a noticable way^^
Most simple solution would probably be to generate said extension-method for all of the above assemblies, which (directly or indirectly) reference Microsoft.Extensions.DempendencyInjection.Abstractions within a namespace preventing collisions.
In above sample solution, that would be in the following namespaces:
Microsoft.Extensions.DependencyInjection.TypealizR.LibraryBMicrosoft.Extensions.DependencyInjection.TypealizR.LibraryCMicrosoft.Extensions.DependencyInjection.TypealizR.LibraryEMicrosoft.Extensions.DependencyInjection.TypealizR.App
or the other way around:
TypealizR.LibraryB.Microsoft.Extensions.DependencyInjectionTypealizR.LibraryC.Microsoft.Extensions.DependencyInjectionTypealizR.LibraryE.Microsoft.Extensions.DependencyInjectionTypealizR.App.Microsoft.Extensions.DependencyInjection
(With or without the TypealizR-prefix)
Such an approach would also work when auto-registrations would need to be generetaed for other containers...
An alternative approach could be to let the source-generator scan referenced assemblies for existence of any present occurence of the generated extension method and incorporate it within its own generation.
Performance benefit could be the fact that there´s a discrete naming-scheme to follow:
namespace Microsoft.Extensions.DependencyInjection.TypealizR.Library.A;
public static TypealizRExtensions{
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromA>>().Typealize());
return services;
}
}
namespace Microsoft.Extensions.DependencyInjection.TypealizR.Library.B;
public static TypealizRExtensions{
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromB>>().Typealize());
return services;
}
}
namespace Microsoft.Extensions.DependencyInjection.TypealizR.Library.C;
public static TypealizRExtensions {
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromC>>().Typealize());
Microsoft.Extensions.DependencyInjection.TypealizR.Library.B.TypealizRExtensions.AddTypealizR(services);
return services;
}
}
namespace Microsoft.Extensions.DependencyInjection.TypealizR.Library.D;
public static TypealizRExtensions {
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromD>>().Typealize());
return services;
}
}
namespace Microsoft.Extensions.DependencyInjection.TypealizR.Library.E;
public static TypealizRExtensions {
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromE>>().Typealize());
Microsoft.Extensions.DependencyInjection.TypealizR.Library.D.TypealizRExtensions.AddTypealizR(services);
return services;
}
}
namespace Microsoft.Extensions.DependencyInjection.TypealizR.App;
public static TypealizRExtensions {
public static IServiceCollection AddTypealizR(this IServiceCollection services) {
services.AddScoped(x => x.GetRequiredService<IStringLocalizer<ResourcesFromApp>>().Typealize());
Microsoft.Extensions.DependencyInjection.TypealizR.Library.A.TypealizRExtensions.AddTypealizR(services);
Microsoft.Extensions.DependencyInjection.TypealizR.Library.B.TypealizRExtensions.AddTypealizR(services);
Microsoft.Extensions.DependencyInjection.TypealizR.Library.C.TypealizRExtensions.AddTypealizR(services);
//Microsoft.Extensions.DependencyInjection.TypealizR.Library.D.TypealizRExtensions.AddTypealizR(services);
Microsoft.Extensions.DependencyInjection.TypealizR.Library.E.TypealizRExtensions.AddTypealizR(services);
return services;
}
}