Ejemplo n.º 1
0
        [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));
 }