Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c#: DI and additional parameter

For example, I have a class CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService with the following dependencies:

    protected readonly IDeviceService _deviceService;
    protected readonly IAzureFunctionLogService _azureFunctionLogService;
    protected readonly IDeviceValidationService _deviceValidationService;

so, I can create ctor for the class:

    public CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService(
        IDeviceService deviceService,
        IDeviceValidationService deviceValidationService,
        IAzureFunctionLogService azureFunctionLogService)
    {
        _deviceService = deviceService;
        _deviceValidationService = deviceValidationService;
        _azureFunctionLogService = azureFunctionLogService;
    }

then inject all dependencies like:

services.AddTransient<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>();
               services.AddSingleton<Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>>(sp =>
                   () => sp.GetRequiredService<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>()
               );

and then use it like this:

    private readonly Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService> _service;


        public FunctionDebugPendingStatusWorkflow(
Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService> service,
            //....
            ILoggerFactory loggerFactory)
        {
            _service = service;
            //....
            _logger = loggerFactory.CreateLogger<FunctionDebugPendingStatusWorkflow>();
        }

so, it works fine.

But how can I add one more param to ctor, which set in caller? For example, I want to pass deviceId to ctor and can't describe it as dependency using dependency injector in Program.cs (in my case)

I have to create "Init" method like this:

    public void Init(int deviceId)
    {
        _device = _deviceService.GetDeviceById(deviceId);
        // ...
    }

and add logic there.

Then I have to call _service.Init(...); before using _service methods. It works, but all disadvantages and potential problems are obviously (if forgot to call etc)

How to pass this parameter using DI ?

like image 578
Oleg Sh Avatar asked Jan 25 '26 14:01

Oleg Sh


1 Answers

You can do something like this:

serviceCollection
    .AddScoped<IYourService>(s => new YourService(
         s.GetService<YourPreviouslyInjectedService1>(),
         s.GetService<YourPreviouslyInjectedService2>(),
         s.GetService<YourPreviouslyInjectedService3>(),
         deviceId
    )
);

But I would advise against it and use IOptions with a configuration object injected like:

.Configure<YourConfigurationWithDeviceIdProperty>(
    c => builder.Configuration.GetSection("YourConfigSectionInAppSettings").Bind(c)
)

First, you are avoiding all this noise in the DI layer and second, you are making sure that you are injecting the correct setting as your constructor would accept a parameter of a specific type and not a primitive which can be anything ("123", "banana", etc).

like image 132
Harun Ćerim Avatar answered Jan 27 '26 03:01

Harun Ćerim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!