-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support class modules and Import(Type, string Factory) #97
Comments
Can you show me a more extended example of what you are imagining, please?
It avoids many hard questions that I'm not sure are worth solving :) Imagine all factories were classes, now all of them need to be instantiated. When does that happen and what do we do with their ctor parameters? What if some services from modules are unused (because they are overridden by other modules)? What if someone wants to resolve another service from a module service factory implementation? |
An example from my tooling in which I use a module and two factories. Current codenamespace Microsoft.DotNet.PackageValidation
{
[ServiceProvider]
[Import(typeof(IServiceLocatorModule))]
[Singleton(typeof(CompatibleFrameworkInPackageValidator))]
[Singleton(typeof(CompatibleTfmValidator))]
[Singleton(typeof(BaselinePackageValidator))]
internal partial class ServiceProvider : IServiceLocatorModule
{
private readonly Func<ISuppressionEngine, ICompatibilityLogger> _logFactory;
private readonly Func<ISuppressionEngine> _suppressionEngineFactory;
// It's important to use GetService<T> here instead of directly invoking the factory
// to avoid two suppression engine being created.
public ICompatibilityLogger LogFactory() => _logFactory(GetService<ISuppressionEngine>());
public ISuppressionEngine SuppressionEngineFactory() => _suppressionEngineFactory();
public ServiceProvider(Func<ISuppressionEngine, ICompatibilityLogger> logFactory,
Func<ISuppressionEngine> suppressionEngineFactory)
{
_logFactory = logFactory;
_suppressionEngineFactory = suppressionEngineFactory;
}
}
[ServiceProviderModule]
[Singleton(typeof(ISuppressionEngine), Factory = nameof(SuppressionEngineFactory))]
[Singleton(typeof(ICompatibilityLogger), Factory = nameof(LogFactory))]
[Singleton(typeof(IApiComparerFactory), typeof(ApiComparerFactory))]
[Singleton(typeof(IAssemblySymbolLoaderFactory), typeof(AssemblySymbolLoaderFactory))]
[Singleton(typeof(IMetadataStreamProvider), typeof(MetadataStreamProvider))]
[Singleton(typeof(IApiCompatRunner), typeof(ApiCompatRunner))]
internal interface IServiceLocatorModule
{
ICompatibilityLogger LogFactory();
ISuppressionEngine SuppressionEngineFactory();
}
} Potential implementation with class modulenamespace Microsoft.DotNet.PackageValidation
{
[ServiceProvider]
[Import(typeof(CommonServiceLocatorModule), Factory = nameof(CreateCommonServiceLocatorModule))]
[Singleton(typeof(CompatibleFrameworkInPackageValidator))]
[Singleton(typeof(CompatibleTfmValidator))]
[Singleton(typeof(BaselinePackageValidator))]
internal partial class ServiceProvider
{
public readonly Func<CompatibilityServiceProviderModule> CreateCommonServiceLocatorModule;
public ServiceProvider(Func<ISuppressionEngine, ICompatibilityLogger> logFactory,
Func<ISuppressionEngine> suppressionEngineFactory)
{
CreateCommonServiceLocatorModule = () => new CommonServiceLocatorModule(logFactory, suppressionEngineFactory);
}
}
[ServiceProviderModule]
[Singleton(typeof(ISuppressionEngine), Factory = nameof(SuppressionEngineFactory))]
[Singleton(typeof(ICompatibilityLogger), Factory = nameof(LogFactory))]
[Singleton(typeof(IApiComparerFactory), typeof(ApiComparerFactory))]
[Singleton(typeof(IAssemblySymbolLoaderFactory), typeof(AssemblySymbolLoaderFactory))]
[Singleton(typeof(IMetadataStreamProvider), typeof(MetadataStreamProvider))]
[Singleton(typeof(IApiCompatRunner), typeof(ApiCompatRunner))]
internal class CommonServiceLocatorModule
{
public readonly Func<ICompatibilityLogger> LogFactory;
public readonly Func<ISuppressionEngine> SuppressionEngineFactory;
public CommonServiceLocatorModule(Func<ISuppressionEngine, ICompatibilityLogger> logFactory,
Func<ISuppressionEngine> suppressionEngineFactory)
{
// It's important to use GetService<T> here instead of directly invoking the factory
// to avoid two suppression engine being created.
LogFactory = () => logFactory(GetService<ISuppressionEngine>());
SuppressionEngineFactory = suppressionEngineFactory;
}
}
} This is just an example with two factories (as I don't use more yet) and with your recent contribution the code become less verbose when using them. I don't know if it's worth introducing the extra complexity but I hope the above example better demonstrates what I was imagining from an API consumption standpoint. |
The following code works: [ServiceProviderModule]
[Import(typeof(IOptionsModule))]
[Singleton(typeof(ILoggerFactory), typeof(LoggerFactory))]
[Singleton(typeof(ILogger<>), typeof(Logger<>))]
[Singleton(typeof(IConfigureOptions<LoggerFilterOptions>), Factory = nameof(CreateFilterOptions))]
public interface ILoggingModule
{
public static IConfigureOptions<LoggerFilterOptions> CreateFilterOptions(LogLevel logLevel) =>
new ConfigureOptions<LoggerFilterOptions>(options => options.MinLevel = logLevel);
} |
It would be great if a module could be defined as a class so that it can have a constructor which is useful when passing in Func factory methods to the module. In the provider itself, the module would then be declared as
[Import(typeof(X), Factory="ModuleFactory")]
.Just in theory, is that possible? What was the reason for choosing an interface over a class for modules?
The text was updated successfully, but these errors were encountered: