I am trying to create an instance of a class at runtime and call the method but it's not working for me.
I have a class library where I have a class and method as below :
Class library MyApp.Service
:
namespace MyApp.Service.SchedularOperations
{
public class WeeklyTaskSchedular : ISchedular
{
private readonly IDbConnection _dbConnection;
private readonly IProductService _productService;
public WeeklyTaskSchedular(IDbConnection dbConnection,IProductService productService)
{
_dbConnection = dbConnection;
_productService = productService;
Frequency = Frequencies.Weekly
}
public Frequencies Frequency { get ; set ; }
public int Process (ScheduleInfo info)
{
//process logic
return 0; indicate success
}
}
}
BackgroundService
project:
namespace MyApp.BackgroundSchedularService
{
public class RunSchedular : BackgroundService
{
private readonly ILogger<RunSchedular> _logger;
private readonly IProductService _productService;
public RunSchedular(ILogger<RunSchedular> logger, IProductService productService)
{
_logger = logger;
_productService = productService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
string connectionString = GetThirdPartyConnectionStringFromDatabase();
string executionClassName = "MyApp.Service.SchedularOperations.WeeklyTaskSchedular"; //coming from database
IDbConnection connection = new SqlConnection(connectionString);
object[] constructorArgs = { connection, _productService};
Type type = GetInstance(executionClassName); //getting null
object instance = Activator.CreateInstance(type,constructorArgs);
object[] methodArgs = { new ScheduleInfo() };
type.GetMethod("Process").Invoke(instance,methodArgs);
await Task.Delay(1000, stoppingToken);
}
}
public Type GetInstance(string strFullyQualifiedName)
{
foreach(var asm in AppDomain.CurrentDomain.GetAssemblies())
{
Type type = asm.GetType(strFullyQualifiedName);
if(type !=null)
return type;
}
return null;
}
}
}
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<RunSchedular>();
services.AddTransient<IProductService, ProductService>();
});
}
Problem is this :
Type type = GetInstance(executionClassName); //getting null
Can someone please help me create an instance of a class at run time with constructor arguments and call the method?
The approach seems wrong to me, you should try to use DI to help with this.
Register all the schedulers as services appropriately:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddTransient<IDbConnection, DbConnection>();
// Notice here that these schedulars are singletons throughout their execution since they will be created under the singleton hosted service RunSchedular.
services.AddTransient<ISchedular, WeeklyTaskSchedular>();
services.AddTransient<ISchedular, DailyTaskSchedular>(); // Made an assumption here this exists also
services.AddHostedService<RunSchedular>();
});
Then inject the framework provided IServiceProvider
and get the service based on the type matching.
public class RunSchedular : BackgroundService
{
private readonly IDbConnection _dbConnection;
private readonly IServiceProvider _serviceProvider;
public RunSchedular(IDbConnection dbConnection, IServiceProvider provider)
{
_dbConnection = dbConnection;
_serviceProvider = provider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
string executionClassName = _dbConnection.GetSchedularType();
ISchedular schedular = _serviceProvider.GetServices<ISchedular>().First(x => x.GetType() == Type.GetType(executionClassName));
schedular.Process(new ScheduleInfo());
await Task.Delay(1000, stoppingToken);
}
}
DBConnection.cs
public string GetSchedularType()
{
// Imagine data access stuff
return "MyApp.Service.SchedularOperations.WeeklyTaskSchedular";
}