When working with .NET Core Dependency Injection, there are situations where not all the constructor parameters can be created and injected directly by the container. This becomes particularly relevant when dealing with legacy code that requires specific constructor parameters that the DI container cannot provide out of the box. In such cases, it becomes necessary to pass parameters to the constructor while resolving the dependency. In this blog post, we will explore the various ways of achieving this in .NET Core. We will demonstrate how to configure and pass parameters to constructors using the AddTransient
, AddSingleton
, and AddScoped
methods, enabling seamless integration of legacy code into your .NET Core application. We will also address the common issue of resolving dependencies with parameters that are not injectable by the DI container, and provide a solution using the factory delegate
of the IServiceProvider
. By the end of this post, you will have a clear understanding of how to pass parameters to constructors in .NET Core DI, allowing you to effectively utilize existing code in your applications.
Step 1:
Set up the Console Application Create a Main.cs
file and include the following code:
Main.cs
void Main()
{
var container = Startup.Configure();
var customerService = container.GetService<ICustomerService>();
customerService.GetData();
}
Step 2:
Implement the Startup Class Create a Startup.cs
file with the following content:
Startup.cs
public class Startup
{
public static ServiceProvider Configure()
{
var provider = new ServiceCollection()
.AddScoped<IDataService,DataService>()
.AddLogging(fs => fs.AddConsole())
.AddTransient<ICustomerService, CustomerService>()
.BuildServiceProvider();
return provider;
}
}
Step 3:
Define Interfaces Create separate files for the IDataService
and ICustomerService
interfaces:
IDataService
public interface IDataService
{
void GetData();
}
public interface ICustomerService
{
void GetData();
}
Step 4:
Implement DataService Create a DataService.cs
file and implement the IDataService
interface:
DataService.cs
public class DataService : IDataService
{
private readonly ILogger _logger;
private readonly string _connectionString;
public DataService(ILogger<DataService> logger, string connectionString)
{
_logger = logger;
_connectionString = connectionString;
}
public void GetData()
{
_logger.LogInformation($"Getting Data From DataBase {_connectionString}");
}
}
Step 5:
Implement CustomerService Implement the CustomerService
class in a separate file:
CustomerService
public class CustomerService : ICustomerService
{
private readonly ILogger<CustomerService> _logger;
private readonly IDataService _dataService;
public CustomerService(ILoggerFactory loggerFactory, IDataService dataService)
{
_logger = loggerFactory.CreateLogger<CustomerService>();
_dataService = dataService;
}
public void GetData()
{
_dataService.GetData();
}
}
If you run the application, you will get the following error because it expects a connection string parameter. After all, that service is not resolved.
Unable to resolve service for type ‘System. String’ while attempting to activate ‘DataService’.{alertError}
Step 6:
To solve this issue, we will introduce the concept of a factory delegate provided by the IServiceProvider
. This delegate allows you to manually create and configure the service instance, providing the necessary parameters at runtime. Modify the Configure
method in Startup.cs
as follows:
public class Startup
{
public static ServiceProvider Configure()
{
var provider = new ServiceCollection()
.AddScoped<IDataService>(x =>
{
var logger = x.GetRequiredService<ILogger<DataService>>();
var dataService = new DataService(logger, "some conection string");
return dataService;
})
.AddLogging(fs => fs.AddConsole())
.AddTransient<ICustomerService, CustomerService>()
.BuildServiceProvider();
return provider;
}
}
If you run the application, you will get the output.
info: DataService[0]
Getting Data From DataBase some conection string
Please reduce the right pane so more of the page productive
ReplyDeleteThanks for the comment I have moved the right pane :)
ReplyDelete