简体   繁体   中英

Initialize components with Autofac 6.4.0 with IComponentRegistration

I migrated from .net 4.6 to .net 4.8 and upgraded Autofac to version 6.4.0. The bellow snippet worked before, but after upgrading, this cannot be done since ResolveComponent method requires ResolveRequest . And ResolveRequest accepts in constructor:

Service service,
ServiceRegistration serviceRegistration,
IEnumerable<Parameter> parameters,
IComponentRegistration? decoratorTarget = null

In the bellow snippet, Container is IContainer Container .

Does anybody has a solution for this?

protected void Application_Start()
    {
    builder.RegisterAssemblyTypes(assemblies)
            .Where(t => (t.Name.EndsWith("ServiceImpl")
                         || t.Name.EndsWith("EngineImpl")
                         || t.Name.EndsWith("Repository")
                         || t.Name.EndsWith("ExportBuilderFactory")
                         || t.Name.EndsWith("HelperImpl")))
            .AsImplementedInterfaces()
            .SingleInstance()
            .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
            .WithProperty(new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == typeof(IDataSource),
                (pi, ctx) => ctx.ResolveKeyed<IDataSource>("DataSource")));
                
        Container = builder.Build();

        // Set the dependency resolver for Web API.
        var webApiResolver = new AutofacWebApiDependencyResolver(Container);
        GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;

        //set the dependency resolver for MVC to be Autofac.
        DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));

        //set the resolver for WCF to be Autofac.
        AutofacHostFactory.Container = Container;
        
        //initialize fully initialized in cache first
        List<IComponentRegistration> componentRegistrations = Container
            .ComponentRegistry.Registrations.Where(r =>
                typeof(IInitializable).IsAssignableFrom(r.Activator.LimitType) &&
                typeof(IFullyInitializedInCacheRepository<>)
                    .IsAssignableFrom(r.Activator.LimitType))
            .ToList();
            
        var resolvedInstances = componentRegistrations.Select(x => Container.ResolveComponent(x, new List<Parameter>())).ToList();

        resolvedInstances.ForEach(x => ((IInitializable)x).Initialize());
    }

Assumptions

In this answer the current design, including the fact that some «repositories» are «initializable» and «initialized» in a certain way, is not questioned.
Instead, the current design is accepted as a limitation.

Overview

It seems that the goal you are trying to achieve is to initialize the initializable repository instances (of initializable repository types).

The type specification from a slightly reformatted piece of source code from the question:

typeof(IInitializable).IsAssignableFrom(r.Activator.LimitType)
&& typeof(IFullyInitializedInCacheRepository<>).IsAssignableFrom(r.Activator.LimitType))

Possible long-term solution

Migrate the repository implementations (classes):

  • From: Implementing the custom interfaces ( IInitializable , etc.).
  • To: Implementing the Autofac.IStartable interface.

For additional details, please, refer to the documentation: Running Code at Container Build — Autofac 6.0.0 documentation .

Possible short-term solution

Let's consider the IInitializable interface.

Introduce an adapter class that will implement the Autofac.IStartable interface to initialize the initializable repository instances.

Please, note that:

  • The adapter accepts the instances of the Autofac.IStartable interface in the constructor.

    When starting, the Start() method will filter the initializable instances to get the initializable repository instances.
    Maybe, this is not optimal to perform such filtering outside Autofac.

  • The adapter will be called by the ContainerBuilder.Build() method.

Draft example program

Program class

using System;
using System.Collections.Generic;
using System.Linq;

using Autofac;

public sealed class Program
{
    public static void Main()
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<InitializableStartable>()
            .As<IStartable>()
            .SingleInstance();
        builder.RegisterType<BookRepository>()
            .As<IFullyInitializedInCacheRepository<Book>>()
            .As<IInitializable>()
            .SingleInstance();
        Console.WriteLine("Program: Created builder");

        IContainer container = builder.Build();
        Console.WriteLine("Program: Built container");

        IFullyInitializedInCacheRepository<Book> bookRepository =
            container.Resolve<IFullyInitializedInCacheRepository<Book>>();
        Console.WriteLine("Program: Resolved book repository");

        bookRepository.GetAll();
        Console.WriteLine("Program: Got all books from repository");
    }

    public interface IFullyInitializedInCacheRepository<T>
    {
        IList<T> GetAll();
    }

    public interface IInitializable
    {
        void Initialize();
    }

    public class Book
    {
    }

    public sealed class BookRepository : IFullyInitializedInCacheRepository<Book>, IInitializable
    {
        public void Initialize()
        {
            Console.WriteLine("BookRepository: Initialized");
        }

        public IList<Book> GetAll()
        {
            Console.WriteLine("BookRepository: Getting books");
            return new List<Book>();
        }
    }

    public sealed class InitializableStartable : IStartable
    {
        private readonly IEnumerable<IInitializable> initializables;

        public InitializableStartable(IEnumerable<IInitializable> initializables)
        {
            this.initializables = initializables;
        }

        public void Start()
        {
            var initializableRepositories = initializables
                .Where(initializable => IsRepositoryType(initializable.GetType()))
                .ToList();
            Console.WriteLine(
                "InitializableStartable: Found initializable repositories: {0}",
                string.Join(";", initializableRepositories)
            );
            foreach (IInitializable initializableRepository in initializableRepositories)
            {
                initializableRepository.Initialize();
            }
        }

        private static bool IsRepositoryType(Type type)
        {
            Type repositoryType = typeof(IFullyInitializedInCacheRepository<>);
            return type.GetInterfaces()
                .Any(x => 
                    x.IsGenericType
                    && x.GetGenericTypeDefinition() == repositoryType
                );
        }
    }
}

Program output

Program: Created builder
InitializableStartable: Found initializable repositories: Program+BookRepository
BookRepository: Initialized
Program: Built container
Program: Resolved book repository
BookRepository: Getting books
Program: Got all books from repository

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM