コード例 #1
0
        /// <summary>
        /// Register a MEF part definition.
        /// </summary>
        /// <param name="builder">The container builder.</param>
        /// <param name="partDefinition">The part definition to register.</param>
        /// <param name="exposedServicesMapper">A mapping function to transform ExportDefinitions into Services.</param>
        public static void RegisterComposablePartDefinition(this ContainerBuilder builder, ComposablePartDefinition partDefinition, Func <ExportDefinition, IEnumerable <Service> > exposedServicesMapper)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }
            if (partDefinition == null)
            {
                throw new ArgumentNullException(nameof(partDefinition));
            }
            if (exposedServicesMapper == null)
            {
                throw new ArgumentNullException(nameof(exposedServicesMapper));
            }

            var partId           = new UniqueService();
            var partRegistration = CreateBasePartRegistration(builder, partDefinition, partId);

            if (IsSharedInstance(partDefinition))
            {
                partRegistration.SingleInstance();
            }

            foreach (var iterExportDef in partDefinition.ExportDefinitions)
            {
                ProcessExportDefinition(builder, exposedServicesMapper, partId, iterExportDef);
            }
        }
コード例 #2
0
        /// <summary>
        /// Register a MEF part definition.
        /// </summary>
        /// <param name="builder">The container builder.</param>
        /// <param name="partDefinition">The part definition to register.</param>
        /// <param name="exposedServicesMapper">A mapping function to transform ExportDefinitions into Services.</param>
        public static void RegisterComposablePartDefinition(this ContainerBuilder builder, ComposablePartDefinition partDefinition, Func <ExportDefinition, IEnumerable <Service> > exposedServicesMapper)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            if (partDefinition == null)
            {
                throw new ArgumentNullException("partDefinition");
            }
            if (exposedServicesMapper == null)
            {
                throw new ArgumentNullException("exposedServicesMapper");
            }

            var partId           = new UniqueService();
            var partRegistration = builder.Register(c => partDefinition.CreatePart())
                                   .OnActivating(e => SetPrerequisiteImports(e.Context, e.Instance))
                                   .OnActivated(e => SetNonPrerequisiteImports(e.Context, e.Instance))
                                   .As(partId);

            if (IsSharedInstance(partDefinition))
            {
                partRegistration.SingleInstance();
            }

            foreach (var iterExportDef in partDefinition.ExportDefinitions)
            {
                var exportDef       = iterExportDef;
                var contractService = new ContractBasedService(exportDef.ContractName, GetTypeIdentity(exportDef));

                var exportId = new UniqueService();
                builder.Register(c =>
                {
                    var p = ((ComposablePart)c.ResolveService(partId));
                    return(new Export(exportDef, () => p.GetExportedValue(exportDef)));
                })
                .As(exportId, contractService)
                .ExternallyOwned()
                .WithMetadata(exportDef.Metadata);

                var additionalServices = exposedServicesMapper(exportDef).ToArray();

                if (additionalServices.Length > 0)
                {
                    builder.Register(c => ((Export)c.ResolveService(exportId)).Value)
                    .As(additionalServices)
                    .ExternallyOwned()
                    .WithMetadata(exportDef.Metadata);
                }
            }
        }
コード例 #3
0
        private static void ProcessExportDefinition(ContainerBuilder builder, Func <ExportDefinition, IEnumerable <Service> > exposedServicesMapper, UniqueService partId, ExportDefinition iterExportDef)
        {
            var exportDef       = iterExportDef;
            var contractService = new ContractBasedService(exportDef.ContractName, GetTypeIdentity(exportDef));
            var exportIsShared  = IsSharedInstance(exportDef);

            var exportId  = new UniqueService();
            var exportReg = builder.Register(c =>
            {
                var p = (ComposablePart)c.ResolveService(partId);
                return(new Export(exportDef, () => p.GetExportedValue(exportDef)));
            })
                            .As(exportId, contractService)
                            .ExternallyOwned()
                            .WithMetadata(exportDef.Metadata);

            // Issue #348: When a constructor takes in a duplicate dependency like:
            //   public ImportsDuplicateMefClass(ImportsMefDependency first, ImportsMefDependency second)
            // and each of those dependencies also take in the same thing:
            //   public ImportsMefDependency(IDependency dependency)
            // Then when the export/import process gets run, if the export doesn't have
            // the same lifetime scope sharing (per-instance vs. singleton) you
            // have trouble because the OnActivating from above in the original part
            // registration doesn't run, the chained-in prerequisite imports never get
            // populated, and everything fails. Setting the export registrations to be
            // the same lifetime scope as the part they correspond to fixes the issue.
            if (exportIsShared)
            {
                exportReg.SingleInstance();
            }

            var additionalServices = exposedServicesMapper(exportDef).ToArray();

            if (additionalServices.Length > 0)
            {
                var addlReg = builder.Register(c => ((Export)c.ResolveService(exportId)).Value)
                              .As(additionalServices)
                              .ExternallyOwned()
                              .WithMetadata(exportDef.Metadata);

                if (exportIsShared)
                {
                    addlReg.SingleInstance();
                }
            }
        }
コード例 #4
0
 private static IRegistrationBuilder <ComposablePart, SimpleActivatorData, SingleRegistrationStyle> CreateBasePartRegistration(ContainerBuilder builder, ComposablePartDefinition partDefinition, UniqueService partId)
 {
     return(builder.Register(c => partDefinition.CreatePart())
            .OnActivating(e => SetPrerequisiteImports(e.Context, e.Instance))
            .OnActivated(e => SetNonPrerequisiteImports(e.Context, e.Instance))
            .As(partId));
 }
コード例 #5
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;
        }