'Initialize interfaces in main form with dependency injection

This my code behind form ExpressionOfNeeds

private readonly IExpressionOfNeeds _expressionOfNeeds;
public FrmExpressionOfNeeds(IExpressionOfNeeds expressionOfNeeds)
{
    InitializeComponent();
    _expressionOfNeeds = expressionOfNeeds;
}
private async void FrmExpressionOfNeeds_Load(object sender, EventArgs e)
{
    GCData.DataSource = await _expressionOfNeeds.GetAllExpressionOfNeeds();
}

and this my code behind MainForm

private readonly IExpressionOfNeeds _expressionOfNeeds;
private readonly IService2 _service2;
private readonly IService3 _service3;
//and so on and so forth
public XtraMain()
{
    InitializeComponent();
}
private void bbtnExpressionOfNeeds_ItemClick(object sender, ItemClickEventArgs e)
{
    FrmExpressionOfNeeds frme = new(_expressionOfNeeds)
    {
        Name = "FrmExpressionOfNeeds"

    };
    ViewChildForm(frme);
}
private void bbtnForm2_ItemClick(object sender, ItemClickEventArgs e)
{
    Form2 frme = new(_service2)
    {
        Name = "Form2"

    };
    ViewChildForm(frme);
}
private void bbtnForm3_ItemClick(object sender, ItemClickEventArgs e)
{
    Form3 frme = new(_service3)
    {
        Name = "Form3"

    };
    ViewChildForm(frme);
}

and so on and so forth
and this is my code behind Program class

static void Main()
{
    var builder = new HostBuilder()
                 .ConfigureServices((hostContext, services) =>
                 {
                     services.AddScoped<XtraMain>();
                     services.AddSingleton<ISqlDataAccess, SqlDataAccess>();
                     services.AddSingleton<IExpressionOfNeeds, ExpressionOfNeeds>();
                 });
    var host = builder.Build();
    using (var serviceScope = host.Services.CreateScope())
    {
        var services = serviceScope.ServiceProvider;
        var mainform = services.GetRequiredService<XtraMain>();
        Application.Run(mainform);
    }
}

the problem is that the value of _expressionOfNeeds is always null and I can't find a way to Initialize it
Update
I have lots of forms and lots of Interfaces
I've only limited it to one example so the code isn't too big.



Solution 1:[1]

You are almost there. You have registered the Form and services into DI container, but forgot to inject the interfaces into your form's constructor.

You have to either add dependent interfaces to the form's constructor (preferred solution), or get an instance of them from the service provider later when you need.

You can find a step by step example in the following post:

Assuming you have a MainForm which has a dependency to IMyServie, then you should have a constructor like this:

IMyService _myService;
public MainForm(IMyService myService)
{
    _myService = myService;
}

Then once you register MainForm and IMyService into the DI container and get the instance from service provider, everything will work as expected. Here is the main entry point:

static class Program
{
    public static IServiceProvider ServiceProvider { get; private set; }

    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();
        var host = CreateHostBuilder().Build();
        ServiceProvider = host.Services;
        Application.Run(ServiceProvider.GetRequiredService<MainForm>());
    }

    static IHostBuilder CreateHostBuilder()
    {
        return Host.CreateDefaultBuilder()
            .ConfigureServices((context, services)=>{
                services.AddTransient<IMyService, MyService>();
                services.AddTransient<MainForm>();
            });
    }
}

If for some reason (like what I explained in the linked answer) you need to get an instance of a service without injecting it in the constructor, then you can use Program.ServiceProvider.GetRequiredService<SomeFormOrService>().

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1