Let's use dependency injection in Winform!

Let's use dependency injection in Winform!

What is dependency injection? Dependency injection is a specific coding technique; for me, the most obvious thing is to solve code coupling.

Last updated 4/22/2022 7:21 AM
AZRNG 鹏祥
4 min read
Category
Winform
Tags
.NET Winform Dependency Injection IOC

Webmaster: There aren't many shared articles about Winform. This technology is relatively mature and has everything it needs. Today, I'm sharing an article about dependency injection in Winform written by another account. I hope developers working on related projects can gain new insights.

1. Introduction

What is dependency injection? Dependency injection is a specific coding technique. For me, the most obvious benefit is reducing code coupling.

2. Purpose

In ASP.NET Core, the container is already set up; you just need to add services to the container. However, in Winform, the default approach still uses the new keyword (even though I've upgraded to .NET 6). Recently, I was adding custom features to an open-source project, and I took the opportunity to upgrade the original .NET Framework to .NET Core. That's when I decided to give dependency injection a try.

I haven't written much C/S code. If there's anything wrong, please correct me.

3. Steps

Example environment for this article: VS2022, .NET 6, Windows Forms Application

4. Preparation

The example includes the following code:

  • Forms: Form1, Form2
  • Services: IUserservice, Userservice, IOrderService, OrderService
public interface IUserservice
{
    string GetName();
}

public class UserService : IUserservice
{
    public string GetName()
    {
        return "IUserservice";
    }
}

public interface IOrderService
{
    string GetName();
}

public class OrderService : IOrderService
{
    public string GetName()
    {
        return "IOrderService";
    }
}

5. Scenario

In Form1, inject IUserservice via the constructor and call the GetName method of IUserservice in the Load event. When the button on the page is clicked, Form2 is displayed. In Form2, inject IOrderService via dependency injection and call the GetName method of IOrderService in the Load event. If the operation can be performed multiple times without errors, it is successful.

6. Getting Started

Reference the component:

<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />

Added a ServiceProviderHelper helper class:

public static class ServiceProviderHelper
{
    /// <summary>
    /// Global service provider
    /// </summary>
    public static IServiceProvider ServiceProvider { get; private set; } = null!;

    /// <summary>
    /// Initialize and build the ServiceProvider object
    /// </summary>
    /// <param name="serviceProvider"></param>
    /// <exception cref="ArgumentNullException"></exception>
    public static void InitServiceProvider(ServiceProvider serviceProvider)
    {
        ArgumentNullException.ThrowIfNull(serviceProvider, nameof(serviceProvider));

        ServiceProvider = serviceProvider;
    }

    /// <summary>
    /// Get Form service
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static Form GetFormService(Type type)
    {
        var service = ServiceProvider.GetRequiredService(type);
        if (service is Form fService)
        {
            return fService;
        }
        else
        {
            throw new ArgumentException($"{type.FullName} is not a Form");
        }
    }

    /// <summary>
    /// Get service
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static T GetService<T>() where T : class
    {
        return ServiceProvider.GetRequiredService<T>();
    }
}

Modify the Program method:

internal static class Program
{
    /// <summary>
    ///  The main entry point for the application.
    /// </summary>
    [STAThread]
    private static void Main()
    {
        // .NET 6 syntax: previously three lines combined into one
        ApplicationConfiguration.Initialize();

        // Create service container
        var services = new ServiceCollection();
        // Add service registrations
        ConfigureServices(services);

        // Build the ServiceProvider object
        ServiceProviderHelper.InitServiceProvider(services.BuildServiceProvider());

        // Get the required service
        var main = ServiceProviderHelper.ServiceProvider.GetRequiredService<Form1>();
        Application.Run(main);
    }

    /// <summary>
    /// Inject services
    /// </summary>
    /// <param name="services"></param>
    public static void ConfigureServices(IServiceCollection services)
    {
        // For batch injection, you can use Scrutor or write your own
        services.AddScoped<IUserservice, UserService>();
        services.AddScoped<IOrderService, OrderService>();

        // Other forms can also be injected here
        services.AddSingleton(typeof(Form1));
        services.AddTransient(typeof(Form2));
    }
}

Perform injection in Form1 and Form2 respectively:

private readonly IUserservice _userservice;

public Form1(IUserservice userservice)
{
    InitializeComponent();
    _userservice = userservice;
}

private readonly IOrderService _orderService;

public Form2(IOrderService orderService) : this()
{
    _orderService = orderService;
}

Click the button on Form1 to display Form2:

private void button1_Click(object sender, EventArgs e)
{
    var form2 = ServiceProviderHelper.GetFormService(typeof(Form2));
    form2.Show();
}

Running the operation several times did not reveal any anomalies.

7. References

Example of implementing dependency injection in Winform based on .NET Core 3.1: http://www.ty2y.com/study/znetcore3.1sjywinformsxylzrsl.html

Keep Exploring

Related Reading

More Articles
Same category / Same tag 2/29/2024

Data Display Can Also Be Done Like This in Winform

In the process of developing Winform, data display functionality is often required. Previously, the gridcontrol control was commonly used. Today, through an example, I would like to introduce how to use the table component from Ant Design Blazor for data display in a Winform Blazor Hybrid application.

Continue Reading
Same category / Same tag 2/29/2024

Can the Winform interface also look good?

A few days ago, I introduced using Blazor Hybrid in Winform, and mentioned that with the Blazor UI, our Winform programs can be designed to look better. Next, I will illustrate with an example of drawing in Winform Blazor Hybrid, hoping it helps you.

Continue Reading