Container Registration
Autofac Modules
Autofac modules are used to add registration components to the system. There automatically discovered from the application domain and installed at startup.
Configuration Over Conventions for Autofac Modules
ApiSettings class represents the application configuration, as is registered in the container as a singleton. To access registrations by configuration, the following base module has been created.
#if NETSTANDARD using Autofac; using EdFi.Ods.Api.Common.Configuration; using EdFi.Ods.Common.Extensions; using System.Linq; using EdFi.Ods.Api.Common.Constants; using log4net; namespace EdFi.Ods.Api.Common.Container { public abstract class ConditionalModule : Module { private readonly ILog _logger = LogManager.GetLogger(typeof(ConditionalModule)); protected readonly ApiSettings ApiSettings; private readonly string _moduleName; protected ConditionalModule(ApiSettings apiSettings, string moduleName) { ApiSettings = apiSettings; _moduleName = moduleName; } public abstract bool IsSelected(); public abstract void ApplyConfigurationSpecificRegistrations(ContainerBuilder builder); protected override void Load(ContainerBuilder builder) { if (IsSelected()) { ApplyConfigurationSpecificRegistrations(builder); } else { _logger.Debug($"{_moduleName} Module is disabled and will not be installed."); } } protected bool IsFeatureEnabled(ApiFeature feature) => ApiSettings.IsFeatureEnabled(feature.GetConfigKeyName()); } } #endif
Windsor Deprecation from Net Core
Windsor is not supported in net core 3.1 and thus is being phased out. This has caused some issues with the chain of responsibility pattern since the original implementation was using a Castle Facility. The base class ChainOfResponsibilityBase<TService, TRequest, TResponse>
is currently used by Pbkdf2HmacSha1SecureHasher
but that component is registered as a regular service.
namespace EdFi.Ods.Api.NetCore.Container.Modules { public class SecureHashingModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<ApiClientAuthenticator>() .As<IApiClientAuthenticator>(); builder.RegisterType<EdFiAdminApiClientIdentityProvider>() .As<IApiClientIdentityProvider>() .As<IApiClientSecretProvider>() .SingleInstance(); builder.RegisterType<PackedHashConverter>() .As<IPackedHashConverter>() .SingleInstance(); builder.RegisterType<SecurePackedHashProvider>() .As<ISecurePackedHashProvider>() .SingleInstance(); builder.RegisterType<DefaultHashConfigurationProvider>() .As<IHashConfigurationProvider>() .SingleInstance(); builder.RegisterType<Pbkdf2HmacSha1SecureHasher>() .As<ISecureHasher>() .SingleInstance(); } } }
The decision to hash or not to hash the secret is defined in the following modules:
using Autofac; using EdFi.Ods.Api.Common.Configuration; using EdFi.Ods.Api.Common.Container; using EdFi.Ods.Common.Security; namespace EdFi.Ods.Api.NetCore.Container.Modules { public class HashedSecretVerifierModule : ConditionalModule { public HashedSecretVerifierModule(ApiSettings apiSettings) : base(apiSettings, nameof(HashedSecretVerifierModule)) { } public override bool IsSelected() => ApiSettings.EncryptSecrets; public override void ApplyConfigurationSpecificRegistrations(ContainerBuilder builder) { builder.RegisterType<SecureHashAwareSecretVerifier>().As<ISecretVerifier>(); builder.RegisterDecorator<AutoUpgradingHashedSecretVerifierDecorator, ISecretVerifier>(); }
and
using System; using Autofac; using EdFi.Ods.Api.Common.Configuration; using EdFi.Ods.Api.Common.Container; using EdFi.Ods.Common.Security; namespace EdFi.Ods.Api.NetCore.Container.Modules { public class PlainTextSecretVerifierModule : ConditionalModule { public PlainTextSecretVerifierModule(ApiSettings apiSettings) : base(apiSettings, nameof(PlainTextSecretVerifierModule)) { } public override bool IsSelected() => !ApiSettings.EncryptSecrets; public override void ApplyConfigurationSpecificRegistrations(ContainerBuilder builder) { builder.RegisterType<PlainTextSecretVerifier>().As<ISecretVerifier>(); } } }