I will try to be very clear.
I am writing a Queue Azure Function in .net7.
I have some Managers that implements an interface. I know which manager instanciate only when a new message arrive.
My managers have only one constructor with an interface in input:
internal class MyNotificationManager : INotificationManager
{
public MyNotificationManager(IContext context)
{ ... }
...
}
Here my Main, where I configure all my services:
public static void Main()
{
string connectionString = System.Environment.GetEnvironmentVariable("DatabaseConnectionString");
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s =>
{
s.AddTransient<IContext, MyDBContext>(c => new MyDBContext(connectionString));
s.AddTransient<INotificationManagerResolver, NotificationManagerResolver>();
...
})
.Build();
host.Run();
}
The NotificationManagerResolver that you see above creates the instance of one of my mager. Here the implementation:
internal class NotificationManagerResolver : INotificationManagerResolver
{
public INotificationManager Resolve(string notificationType)
{
...
var type = Assembly.GetAssembly(typeof(NotificationManagerResolver))
.GetType(concreteType);
var instance = Activator.CreateInstance(type);
return instance as INotificationManager;
}
}
In the function, I try to resolve the manager:
private readonly INotificationManagerResolver _notificationManagerResolver;
...
[Function("MyFunction")]
public async Task Run([QueueTrigger("%QueueName%", Connection = "StorageConnectionString")] string queueItem)
{
var notificationManager = _notificationManagerResolver.Resolve(c.NotificationType);
}
Obviously I get an error when I try to resolve and instanciate my manager, because it does not know how resolve the IContext in input in the constructor of the manager, even though I defined the mapping in the Main.
I can easily resolve the problem removing the line
s.AddTransient<IContext, MyDBContext>(c => new MyDBContext(connectionString));
from the Main and modifying the resolver. If I change the line
var instance = Activator.CreateInstance(type);
with this line
var instance = Activator.CreateInstance(type, new MyDBContext(connectionString));
everything works correctly.
But I don't like the solution. I do not want to bind the resolver to the definition of IContext.
Any suggestion please?
Thank you
If you want to register all existing implementation of
INotificationManagerwithout explicitly listing all its types in the code, you can perform the assembly scan and find all implementations at runtime. Then use DI container to resolve the exact implementation you need. To do so:Add
scrutornuget-package to support assembly scan capabilities.Modify your registration code in the following way scan assembly, containing the
NotificationManagerResolvertype for types that implementsINotificationManagerinterfaceModify
NotificationManagerResolverto get service provider as dependency and then use it to resolve managers