Here's my problem: I have a container where I register concrete types as interfaces.
builder.RegisterType<DeleteOrganization>().As<IDeleteOrganization>();
I'm implementing a SerializationBinder
for a serialization project I'm doing and the BindToType
method that I need to implement wants me to return a Type
object. The BindToType
method gives me an assemblyName
and typeName
(both strings) to help me create a type object. What I want to do is if the typeName
is an interface, I want to ask Autofac what the concrete implementation Type
is for that interface Type
without actually having it create the object. Is that possible?
If you are using the RegisterType to register your services this is possible. I wrote a quick test that should help you extract the data you need.
private interface IDeleteOrganization
{
}
private class DeleteOrganization : IDeleteOrganization
{
}
[TestMethod]
public void CanResolveConcreteType()
{
var builder = new ContainerBuilder();
builder.RegisterType()
.As();
using(var container = builder.Build())
{
var registration = container.ComponentRegistry
.RegistrationsFor(new TypedService(typeof (IDeleteOrganization)))
.SingleOrDefault();
if (registration != null)
{
var activator = registration.Activator as ReflectionActivator;
if (activator != null)
{
//we can get the type
var type = activator.LimitType;
Assert.AreEqual(type, typeof (DeleteOrganization));
}
}
}
}
You can very nicely encapsulate @Danielg's method so that you can let Autofac inject the type-list into a construtor. It requires you to implement the IRegistrationSource
.
In my case I wanted to get all registered types derived from IConsoleCommand
like that:
public Help(TypeList<IConsoleCommand> commands)
{
_commands = commands;
}
I used a simple DTO-List to carry the types and the T
that I wanted to resolve them for:
public class TypeList<T> : List<Type>
{
public TypeList(IEnumerable<Type> types) : base(types)
{
}
}
The actual registration source is implemented as following where the <T>
from the TypeList<T>
is used to match the type of interface that is registered and that we want to retrieve.
internal class TypeListSource<T> : IRegistrationSource
{
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (service is IServiceWithType swt && typeof(TypeList<T>).IsAssignableFrom(swt.ServiceType))
{
var registration =
new ComponentRegistration(
id: Guid.NewGuid(),
activator: new DelegateActivator(swt.ServiceType, (context, p) =>
{
var types =
context
.ComponentRegistry
.RegistrationsFor(new TypedService(typeof(T)))
.Select(r => r.Activator)
.OfType<ReflectionActivator>()
.Select(activator => activator.LimitType);
return new TypeList<T>(types);
}),
services: new[] {service},
lifetime: new CurrentScopeLifetime(),
sharing: InstanceSharing.None,
ownership: InstanceOwnership.OwnedByLifetimeScope,
metadata: new Dictionary<string, object>()
);
return new IComponentRegistration[] {registration};
}
// It's not a request for the base handler type, so skip it.
else
{
return Enumerable.Empty<IComponentRegistration>();
}
}
public bool IsAdapterForIndividualComponents => false;
}
Finally you have to add it to the builder
with:
builder.RegisterSource(new TypeListSource<IConsoleCommand>());
Now Autofac can resolve the types with dependency injection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With