[CLSCompliant(false)] // `IServiceCollection` is not CLSCompliant. protected internal ApplicationDependencyInjection(ApplicationDependencyInjectionConfiguration configuration, IServiceCollection services) { // Validate: if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } if (services is null) { throw new ArgumentNullException(nameof(services)); } // if (!_semaphore.Wait(millisecondsTimeout: 0)) { throw new InvalidOperationException("Another " + nameof(ApplicationDependencyInjection) + " has already been created in this AppDomain without being disposed first (or the previous dispose attempt failed)."); } this.Configuration = configuration.ToImmutable(); // Register necessary internal services: services.TryAddDefaultDependencyInjectionOverrideService(); services.TryAddSingleton <IServiceProviderAccessor>(sp => new AspNetDependencyInjection.Services.DefaultServiceProviderAccessor(this.Configuration, sp)); services.TryAddSingleton <ObjectFactoryCache>(); // Initialize fields: this.services = services; this.rootServiceProvider = services.BuildServiceProvider(validateScopes: true); this.ObjectFactoryCache = this.rootServiceProvider.GetRequiredService <ObjectFactoryCache>(); // HostingEnvironment.RegisterObject(this); global::Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(HttpContextScopeHttpModule)); // NOTE: It is not possible to un-register a HttpModule. That's nothing to do with `Microsoft.Web.Infrastructure` - the actual module registry in `System.Web.dll` can only be added to, not removed from. }
// There exists a mutual-reference dependenecy problem here: // * `IDependencyInjectionClient` depends on a valid `ApplicationDependencyInjection` // * `ApplicationDependencyInjection` needs to own the `IDependencyInjectionClient` instances. // * But `ApplicationDependencyInjection` can't simply create the `IDependencyInjectionClient` instances from within its constructor because that would have to be a virtual method (constructors should not call virtual methods). // However, there's two solutions: // * Define a new *outer* class that creates the `ApplicationDependencyInjection` via a virtual method (which can create a subclass) // * And this outer-class then owns the `IDependencyInjectionClient` instances. // Ugh, I wish C# had a way to define immutable aggregates easily. // The other solution is that `ApplicationDependencyInjection` still owns the `IDependencyInjectionClient` instances, but the outer-object that creates them is this (ApplicationDependencyInjectionBuilder). // This is acceptable because `ApplicationDependencyInjection` never exposes an intermediate-state `ApplicationDependencyInjection` instance to consumers - it all happens inside `Build`. /// <summary>Calls <see cref="CreateAndConfigureServiceCollection"/>, then <see cref="Create(ApplicationDependencyInjectionConfiguration,IServiceCollection)"/>, then <see cref="ApplicationDependencyInjection.CreateClients(IEnumerable{Func{ApplicationDependencyInjection, IServiceProvider, IDependencyInjectionClient}})"/></summary> public virtual ApplicationDependencyInjection Build() { ApplicationDependencyInjectionConfiguration configuration = this.configuration ?? new ApplicationDependencyInjectionConfiguration(); IServiceCollection services = this.CreateAndConfigureServiceCollection(); // If a consumer subclasses `ApplicationDependencyInjectionConfiguration` then their constructor has to complete first before creating Clients. // This is so that we don't pass an incomplete `ApplicationDependencyInjectionConfiguration` instance into a Client's constructor. // After they're created, they're then saved in `built`. ApplicationDependencyInjection built = this.Create(configuration, services); try { built.CreateClients(this.clientFactories); return(built); } catch { built.Dispose(); throw; } }
/// <summary>Sets the internal <see cref="ApplicationDependencyInjectionConfiguration"/> field. Can be null (in which case the defualt <see cref="ApplicationDependencyInjectionConfiguration"/> will be used).</summary> public virtual ApplicationDependencyInjectionBuilder UseConfiguration(ApplicationDependencyInjectionConfiguration configuration) { this.configuration = configuration; return(this); }
/// <summary>Factory for the <see cref="ApplicationDependencyInjection"/> instance. Overriden versions may return a subclass of <see cref="ApplicationDependencyInjection"/>. Implementations should not call any other virtual methods on this object.</summary> protected virtual ApplicationDependencyInjection Create(ApplicationDependencyInjectionConfiguration configuration, IServiceCollection services) { return(new ApplicationDependencyInjection(configuration, services)); }