Trimming constructor arguments with dependency injection: MVVM and the .NET Host

How DI simplifies object creation, and how the .NET Generic Host keeps the ever-growing constructors of MVVM view models short.

Dependency injection (DI) makes object creation easy. It looks up the pre-registered objects that match a constructor signature, passes them in, and raises a build error when a registration is missing.

You no longer hand-write long argument lists every time you construct an instance, which also helps readability.

Why it shines in MVVM

The services and databases an app uses are likely to be needed by nearly every view model in an MVVM codebase. That naturally inflates the constructor argument count. Being able to keep it short through DI — hosting, for instance — is a big win.

Constructing everything by hand looks like this:

var vm = new MainViewModel(
    new UserService(new HttpClient(), logger),
    new SettingsService(config),
    new AppDbContext(connectionString),
    logger,
    /* ... */);

Register the services once, and a view model only has to declare what it needs in its constructor.

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

var host = Host.CreateDefaultBuilder()
    .ConfigureServices((context, services) =>
    {
        services.AddSingleton<IUserService, UserService>();
        services.AddSingleton<ISettingsService, SettingsService>();
        services.AddDbContext<AppDbContext>();
        services.AddTransient<MainViewModel>();
    })
    .Build();

// The host fills in the constructor arguments on its own
var vm = host.Services.GetRequiredService<MainViewModel>();
public class MainViewModel
{
    public MainViewModel(
        IUserService userService,
        ISettingsService settingsService,
        AppDbContext db)
    {
        // The registered instances are injected automatically
    }
}

It absorbs constructor changes

The other benefit of DI shows up when constructor arguments change.

If you call constructors directly, adding one argument means hunting down every call site and editing it. With DI the host service passes the required objects automatically, so changing a constructor signature leaves the call sites untouched. And if you ask for a dependency that was never registered, it surfaces immediately at runtime — so omissions get caught quickly too.