Dependency Injection

Apps built using hosting can leverage dependency injection (DI) to register services and make them available to app dependencies. This pattern enables apps to follow sound design principles, such as SOLID and Inversion of Control. While the host builder implements standard functionality from the Microsoft.Extensions.DependencyInjection library, it also provides additional features to improve the developer experience.

Registering Services

Services are registered with the host using the ConfigureServices method on the IHostBuilder. The following snippet shows how to register a service with the host:

private IHost Host { get; }

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    var appBuilder = this.CreateBuilder(args)
        .Configure(host =>
        {
            host
            .ConfigureServices((context, services) =>
            {
                services.AddSingleton<SimpleService>();
            })
        });

    Host = appBuilder.Build();
    ...
}

Before the IHost instance is created, the ConfigureServices method is called to register services with the host. The ConfigureServices method is called from the lambda expression passed into the Configure method. ConfigureServices itself takes two parameters: a HostBuilderContext and an IServiceCollection. The HostBuilderContext provides access to the host's configuration and environment. The IServiceCollection is used to register services with the host.

Resolving Services

The recommended way to resolve services is to use constructor injection. The following snippet shows how to resolve a service from the host:

public class SimpleViewModel : ObservableObject
{
    public SimpleViewModel(ISimpleService service)
    {
        Service = service;
    }

    public ISimpleService Service { get; }
}

Services can also be resolved from an IHost instance:

var service = Host.Services.GetService<ISimpleService>();

Service Lifetimes

Services can be registered with the host using different lifetimes. The following table shows the different service lifetimes:

Lifetime Description
Transient A new instance of the service is created each time it is requested.
Scoped A single instance of the service is created per scope.
Singleton A single instance of the service is created for the lifetime of the host.

Typically, services are registered with the Singleton lifetime.

Named Services

Uno.Extensions provides a way to register multiple services of the same type with different names. This is useful in scenarios where multiple implementations of the same service are configured differently in an implementation factory and the correct implementation needs to be resolved at runtime. The following snippet shows how to register a named service with the host:

private IHost Host { get; }

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    var appBuilder = this.CreateBuilder(args)
        .Configure(host =>
        {
            host
            .ConfigureServices((context, services) =>
            {
                services.AddNamedSingleton<ISimpleService, SimpleService>("SimpleNamedServiceOne");
                services.AddNamedSingleton<ISimpleService, SimpleService>("SimpleNamedServiceTwo");
            })
        });

    Host = appBuilder.Build();
    ...
}

Services can be resolved by name using the GetNamedService extension method:

var service = Host.Services.GetNamedService<ISimpleService>("SimpleNamedServiceOne");

Service Implementation Factories

Uno.Extensions provides a way to register services using a factory method. This is useful in scenarios where the service implementation is not known until runtime. The following snippet shows how to register a service with the host using a factory method:

private IHost Host { get; }

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    var appBuilder = this.CreateBuilder(args)
        .Configure(host =>
        {
            host
            .ConfigureServices((context, services) =>
            {
                services.AddSingleton<ISimpleService>(serviceProvider =>
                {
                    var configuration = serviceProvider.GetRequiredService<IConfiguration>();
                    var simpleService = new SimpleService();
                    simpleService.Configure(configuration);
                    return simpleService;
                });
            })
        });

    Host = appBuilder.Build();
    ...
}