I am trying to use autofac to register open generic type to resolve to derived type
public interface IBackGroundJobHandler<T> where T: INotification
{
public Task Handle(T notification, CancellationToken cancellationToken);
}
public abstract class EventHandler<T> : IBackGroundJobHandler<T> where T : INotification
{
public abstract Task Handle(T notification, CancellationToken cancellationToken);
}
public class TestEventHandler : EventHandler<TestEvent>
{
public async override Task Handle(TestEvent notification, CancellationToken
cancellationToken)
{
await Task.Delay(20000);
System.Diagnostics.Debug.WriteLine("Test Event Finished");
}
}
public class SomeService<T> where T:INotfication
{
public SomeService(IBackGroundJobHandler<T> handler)
{
//sometask
}
}
I tried registering it by :
builder.RegisterGeneric(typeof(EventHandler<>)).As(typeof(IBackGroundJobHandler<>))
.InstancePerLifetimeScope();
IBackgroundJobHandler is not resolving in service constructor.
I also tried:
builder.RegisterAssemblyTypes(typeof(EventHandler).GetTypeInfo().Assembly)
.AsClosedTypesOf(typeof(IBackGroundJobHandler<>)).InstancePerLifetimeScope();
I am new to autofac, how can I resolve this?
CodePudding user response:
I avoided abstract class and simply used generic interface IBackGroundJobHandler<>
public class TestEventHandler : IBackGroundJobHandler<TestEvent>
{
public async override Task Handle(TestEvent notification, CancellationToken
cancellationToken)
{
//Task
}
}
Registered in Autofac container as:
builder.RegisterAssemblyTypes(typeof(IBackGroundEventHandler<>)
.GetTypeInfo().Assembly)
.AsClosedTypesOf(typeof(IBackGroundEventHandler<>))
.InstancePerLifetimeScope()
.AsImplementedInterfaces();
CodePudding user response:
EventHandler<T> is an abstract class, so the Autofac resolver will not be able to create one anyway.
You've not registered TestEventHandler (for example), so Autofac is unaware of it.
When you request a IBackGroundJobHandler<TestEvent>, I presume that you want to get a TestEventHandler resolved, but that class has not been registered.
So, given that you need to register TestEventHandler, you probably don't need that EventHandler<T> abstract class anyway. (I'm guessing that you thought that would be a way of registering all classes that derived from EventHandler<T> in on go). The TestEventHandler can just implement IBackGroundJobHandler<TestEvent>.
class TestEventHandler : IBackGroundJobHandler<TestEvent>
{
public async Task Handle(TestEvent notification, CancellationToken cancellationToken)
{
// Process the Test Event
}
}
Then use:
builder.RegisterType<TestEventHandler>()
.As<IBackGroundJobHandler<TestEvent>>()
.InstancePerLifetimeScope();
If you have many event handlers, it can be a pain, so I'd use reflection to find the classes that do implement the interface:
// Get the assembly that contains the implementors, assuming
// they are all in the same assembly as the TestEventHandler:
Assembly assembly = typeof(TestEventHandler).Assembly;
// Get all classes from assembly that implement the required interface
Type[] classesThatImplementIBackGroundJobHandler = assembly.GetTypes()
.Where(t => t.IsClass
&& t.GetInterfaces().Any(i =>
i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IBackGroundJobHandler<>).GetGenericTypeDefinition())).ToArray();
// Register All Types that Implement our interface
builder.RegisterTypes(classesThatImplementIBackGrounJobHandler)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
.