Exemplo n.º 1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PoolGetActivator{TLimit}"/> class.
 /// </summary>
 /// <param name="poolService">The service used to access the pool.</param>
 /// <param name="registrationPolicy">The registration policy for the pool.</param>
 public PoolGetActivator(PoolService poolService, IPooledRegistrationPolicy <TLimit> registrationPolicy)
 {
     _poolService        = poolService;
     _registrationPolicy = registrationPolicy;
 }
Exemplo n.º 2
0
        private static void RegisterPooled <TLimit, TActivatorData, TSingleRegistrationStyle>(
            IRegistrationBuilder <TLimit, TActivatorData, TSingleRegistrationStyle> registration,
            IPooledRegistrationPolicy <TLimit> registrationPolicy,
            object[]?tags)
            where TSingleRegistrationStyle : SingleRegistrationStyle
            where TActivatorData : IConcreteActivatorData
            where TLimit : class
        {
            if (registration == null)
            {
                throw new ArgumentNullException(nameof(registration));
            }

            // Mark the lifetime appropriately.
            var regData = registration.RegistrationData;

            regData.Lifetime = new PooledLifetime();
            regData.Sharing  = InstanceSharing.None;

            var callback = regData.DeferredCallback;

            if (callback is null)
            {
                throw new NotSupportedException(RegistrationExtensionsResources.RequiresCallbackContainer);
            }

            if (registration.ActivatorData.Activator is ProvidedInstanceActivator)
            {
                // Can't use provided instance activators with pooling (because it would try to repeatedly activate).
                throw new NotSupportedException(RegistrationExtensionsResources.CannotUseProvidedInstances);
            }

            var original = callback.Callback;

            Action <IComponentRegistryBuilder> newCallback = registry =>
            {
                // Only do the additional registrations if we are still using a PooledLifetime.
                if (!(regData.Lifetime is PooledLifetime))
                {
                    original(registry);
                    return;
                }

                var pooledInstanceService = new UniqueService();

                var instanceActivator = registration.ActivatorData.Activator;

                if (registration.ResolvePipeline.Middleware.Any(c => c is CoreEventMiddleware ev && ev.EventType == ResolveEventType.OnRelease))
                {
                    // OnRelease shouldn't be used with pooled instances, because if a policy chooses not to return them to the pool,
                    // the Disposal will be fired, not the OnRelease call; this means that OnRelease wouldn't fire until the container is disposed,
                    // which is not what we want.
                    throw new NotSupportedException(RegistrationExtensionsResources.OnReleaseNotSupported);
                }

                // First, we going to create a pooled instance activator, that will be resolved when we want to
                // **actually** resolve a new instance (during 'Create').
                // The instances themselves are owned by the pool, and will be disposed when the pool disposes
                // (or when the instance is not returned to the pool).
                var pooledInstanceRegistration = new ComponentRegistration(
                    Guid.NewGuid(),
                    instanceActivator,
                    RootScopeLifetime.Instance,
                    InstanceSharing.None,
                    InstanceOwnership.ExternallyOwned,
                    registration.ResolvePipeline,
                    new[] { pooledInstanceService },
                    new Dictionary <string, object?>());

                registry.Register(pooledInstanceRegistration);

                var poolService = new PoolService(pooledInstanceRegistration);

                var poolRegistration = new ComponentRegistration(
                    Guid.NewGuid(),
                    new PoolActivator <TLimit>(pooledInstanceService, registrationPolicy),
                    RootScopeLifetime.Instance,
                    InstanceSharing.Shared,
                    InstanceOwnership.OwnedByLifetimeScope,
                    new[] { poolService },
                    new Dictionary <string, object?>());

                registry.Register(poolRegistration);

                var pooledGetLifetime = tags is null ? CurrentScopeLifetime.Instance : new MatchingScopeLifetime(tags);

                // Next, create a new registration with a custom activator, that copies metadata and services from
                // the original registration. This registration will access the pool and return an instance from it.
                var poolGetRegistration = new ComponentRegistration(
                    Guid.NewGuid(),
                    new PoolGetActivator <TLimit>(poolService, registrationPolicy),
                    pooledGetLifetime,
                    InstanceSharing.Shared,
                    InstanceOwnership.OwnedByLifetimeScope,
                    regData.Services,
                    regData.Metadata);

                registry.Register(poolGetRegistration);

                // Finally, add a service pipeline stage to just before the sharing middleware, for each supported service, to extract the pooled instance from the pool instance container.
                foreach (var srv in regData.Services)
                {
                    registry.RegisterServiceMiddleware(srv, new PooledInstanceUnpackMiddleware <TLimit>(), MiddlewareInsertionMode.StartOfPhase);
                }
            };

            callback.Callback = newCallback;
        }