Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Use the .NET Generic Host in a Windows Forms app

The .NET Generic Host provides a standardized way to configure and run applications with built-in support for dependency injection (DI), configuration, and logging. Windows Forms apps don't include Generic Host integration by default, but you can add it. This article shows how to set up the Generic Host in a Windows Forms app to inject services into your forms.

Prerequisites

Set up the Generic Host

The setup differs slightly between C# and Visual Basic. In C#, configure the host directly in Program.cs. In Visual Basic, use the Application Framework's startup and shutdown events in ApplicationEvents.vb.

Configure the host in Program.cs alongside ApplicationConfiguration.Initialize():

  1. Call ApplicationConfiguration.Initialize() to configure WinForms defaults, including visual styles, high DPI mode, and default fonts.
  2. Build the host with CreateApplicationBuilder and register services.
  3. Start the host and resolve the main form from DI.
  4. Pass the form to Run.
  5. Stop and dispose of the host after the form closes.

The following code shows the complete Program.cs:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace HostBuilderApp;

static class Program
{
 [STAThread]
 static void Main()
 {
 ApplicationConfiguration.Initialize();

 var builder = Host.CreateApplicationBuilder();

 builder.Services.AddHostedService<SampleLifecycleService>();
 builder.Services.AddTransient<Form1>();
 builder.Services.AddSingleton<IGreetingService, GreetingService>();

 IHost host = builder.Build();

 host.Start();

 Form1 mainForm = host.Services.GetRequiredService<Form1>();
 Application.Run(mainForm);

 host.StopAsync().GetAwaiter().GetResult();
 host.Dispose();
 }
}

Register and consume services

With the host configured, register custom services and inject them into your forms. To create and register a service:

  1. Define a service interface:

    public interface IGreetingService
    {
     string GetGreeting();
    }
    
    Public Interface IGreetingService
     Function GetGreeting() As String
    End Interface
    
  2. Create a class that implements the interface. The GreetingService class injects IConfiguration to read the greeting message from appsettings.json:

    public class GreetingService : IGreetingService
    {
     private readonly IConfiguration _configuration;
    
     public GreetingService(IConfiguration configuration)
     {
     _configuration = configuration;
     }
    
     public string GetGreeting()
     {
     return _configuration.GetValue<string>("GreetingMessage")
     ?? "Hello, World!";
     }
    }
    
    Public Class GreetingService
     Implements IGreetingService
    
     Private ReadOnly _configuration As IConfiguration
    
     Public Sub New(configuration As IConfiguration)
     _configuration = configuration
     End Sub
    
     Public Function GetGreeting() As String Implements IGreetingService.GetGreeting
     Dim message As String = _configuration.GetValue(Of String)("GreetingMessage")
    
     If message Is Nothing Then
     Return "Hello, World!"
     End If
    
     Return message
     End Function
    
    End Class
    
  3. Register the interface and implementation on the builder's Services property, as shown in the Set up the Generic Host section.

Run a hosted service

The Generic Host can also run background services that participate in the application lifecycle. Implement IHostedService to receive callbacks when the host starts and stops. To add a hosted service:

  1. Create a class that implements IHostedService. The following class writes to the debug output when the host starts and stops:

    public class SampleLifecycleService : IHostedService
    {
     public Task StartAsync(CancellationToken cancellationToken)
     {
     System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Started.");
     return Task.CompletedTask;
     }
    
     public Task StopAsync(CancellationToken cancellationToken)
     {
     System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Stopped.");
     return Task.CompletedTask;
     }
    }
    
    Public Class SampleLifecycleService
     Implements IHostedService
    
     Public Function StartAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StartAsync
     System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Started.")
     Return Task.CompletedTask
     End Function
    
     Public Function StopAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StopAsync
     System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Stopped.")
     Return Task.CompletedTask
     End Function
    
    End Class
    
  2. Register the service with AddHostedService on the builder's Services property, as shown in the Set up the Generic Host section.

The host calls StartAsync on startup and StopAsync on shutdown, so the debug output appears in the Output window in Visual Studio.

Consume services in a form

Because Form1 is resolved from the DI container, constructor injection works directly:

  1. Add constructor parameters for each service the form needs.
  2. Store the injected services in private fields.
  3. Use the services in event handlers or other methods.
public partial class Form1 : Form
{
 private readonly ILogger<Form1> _logger;
 private readonly IGreetingService _greetingService;

 public Form1(ILogger<Form1> logger, IGreetingService greetingService)
 {
 InitializeComponent();

 _logger = logger;
 _greetingService = greetingService;
 }

 private void ButtonGreet_Click(object sender, EventArgs e)
 {
 string greeting = _greetingService.GetGreeting();
 lblGreeting.Text = greeting;
 _logger.LogInformation("Greeting displayed: {Greeting}", greeting);
 }
}
Public Class Form1

 Private _logger As ILogger(Of Form1)
 Private _greetingService As IGreetingService

 Sub New(ILogger As ILogger(Of Form1), greetingService As IGreetingService)
 InitializeComponent()
 _logger = ILogger
 _greetingService = greetingService
 End Sub

 Private Sub ButtonGreet_Click(sender As Object, e As EventArgs) Handles btnGreet.Click
 Dim greeting As String = _greetingService.GetGreeting()
 lblGreeting.Text = greeting
 _logger.LogInformation("Greeting displayed: {Greeting}", greeting)
 End Sub

End Class

Add configuration

CreateApplicationBuilder automatically loads appsettings.json from the output directory. To add a configuration file:

  1. Create an appsettings.json file in the project root with your configuration values:

    {
     "GreetingMessage": "Hello from the Generic Host!"
    }
    
  2. Set CopyToOutputDirectory to PreserveNewest in the project file so appsettings.json is copied to the output directory:

    <Project Sdk="Microsoft.NET.Sdk">
    
     <PropertyGroup>
     <OutputType>WinExe</OutputType>
     <TargetFramework>net10.0-windows</TargetFramework>
     <Nullable>enable</Nullable>
     <ImplicitUsings>enable</ImplicitUsings>
     <UseWindowsForms>true</UseWindowsForms>
     </PropertyGroup>
    
     <ItemGroup>
     <None Update="appsettings.json">
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
     </ItemGroup>
    
     <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.*" />
     </ItemGroup>
    
    </Project>
    

Related content


Feedback

Was this page helpful?

Additional resources