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());
}
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.
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))
Migrate the repository implementations (classes):
IInitializable
, etc.).Autofac.IStartable
interface. For additional details, please, refer to the documentation: Running Code at Container Build — Autofac 6.0.0 documentation .
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.
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: 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.